Firebase Hosting rewrite 怎么用

Firebase Hosting 的 rewrite 能把 URL 映射到 function、Cloud Run 或 SPA。本文讲清楚四种真正合理的用法,以及每种的隐藏陷阱。

rewrite 是 Firebase Hosting 里最常被滥用的功能。用对了,SPA 能跑、动态路由能命中 Cloud Function;用错了,要么静默把站的 SEO 拍扁,要么返回空白页。本文走一遍四种真正合理的用法,并指出每种的陷阱。

问题背景

firebase.json 里的 rewrite 告诉 CDN:“用户请求 X 时,返回 Y”。Y 可以是另一个静态文件、Cloud Function、Cloud Run 服务,或者另一个 Hosting 站点。rewrite 在 404 兜底之前生效,所以它覆盖所有”没对应真实文件”的 URL。这种威力是为什么大家爱复制粘贴自己根本看不懂的 rewrite 块。

判断标准

  • 你有 SPA,希望 /任何路径 都载入 /index.html
  • 你想让 /api/* 命中 Cloud Function 或 Cloud Run。
  • 你想把一个路径别名到另一个(比如 /blog/* 指向 /articles/*)。
  • 你想在某个路径下挂另一个 Firebase Hosting 站点。

快速结论

只在上面四种情况用 rewrite。URL 真的要换路径就用 redirects(301)。多页静态站大多数情况完全不需要 rewrite。

实操步骤

  1. 先想清楚你到底是哪一种:SPA、动态后端、路径别名、还是多站点。混着用就是 bug 源头。

  2. SPA 模式。 只在有 client-side 路由(React Router / Vue Router)的应用里用。多页静态站千万别这么干:

{
  "hosting": {
    "public": "dist",
    "rewrites": [
      { "source": "**", "destination": "/index.html" }
    ]
  }
}
  1. 动态后端模式。 限定前缀,绝不把整个 ** 指给 function。同时挂 Cloud Function 和 Cloud Run 的示例:
{
  "hosting": {
    "public": "dist",
    "rewrites": [
      { "source": "/api/v1/**", "function": "api", "region": "us-central1" },
      { "source": "/og/**",     "run":      { "serviceId": "og-image", "region": "us-west1" } }
    ]
  }
}

region 必须和 Cloud Function 实际部署的区域一致——部署成功后报「function not found」,最常见原因就是 region 对不上。

  1. 多站点模式。 在某路径下挂另一个 Hosting 站点,状态页 / 文档子站常用:
{
  "hosting": {
    "site": "marketing",
    "public": "dist",
    "rewrites": [
      { "source": "/docs/**", "site": "docs" }
    ]
  }
}
  1. 重命名 / 搬迁 URL 用 redirects,不要用 rewrite——搜索引擎要靠 301 更新索引:
{
  "hosting": {
    "redirects": [
      { "source": "/blog/:slug",     "destination": "/articles/:slug", "type": 301 },
      { "source": "/old/**",         "destination": "/new/:0",         "type": 301 }
    ]
  }
}
  1. 部署完用无痕 + curl 验证:
firebase deploy --only hosting

# 真实静态文件,直接命中
curl -sI https://yourdomain.com/about.html | head -1
# HTTP/2 200

# API 路径走函数
curl -sI https://yourdomain.com/api/v1/health | head -1
# HTTP/2 200

# 老 URL 301 跳转
curl -sI https://yourdomain.com/blog/foo | grep -E 'HTTP|location'
# HTTP/2 301
# location: https://yourdomain.com/articles/foo
  1. 前 24 小时盯日志。如果爬虫在 rewrite 路径上拉静态资源(*.png*.css),说明规则太宽:
firebase functions:log --only api --lines 200 | grep -E '\.(png|css|js|ico)' | head
# 任何输出 = 通配符匹配过头了

容易踩的坑

  • 多页站做 ** -> /index.html——所有 URL 都变成同一份 HTML,SEO 直接挂。
  • 把所有流量都塞 Cloud Function——慢、贵、没必要。
  • 该用 redirect 的地方用了 rewrite。rewrite 不改 URL,redirect 才改。
  • 忘了 rewrite 不会改地址栏——搜索引擎看到的还是原路径。
  • 没考虑 cleanUrls 的影响——cleanUrls: true/about.html/about 提供服务,rewrite 可能不匹配。

这篇适合谁

有 client-side 路由的 SPA、用 Cloud Functions / Run 做 API 的站、想共用域名挂多个站点的项目。

这篇不适合谁

纯多页静态站;需要真正 URL 变更的站(用 redirect);流量主要走 SSR 的应用——选框架原生平台。

FAQ

  • rewrite 和 redirect 有什么区别?: rewrite 保持 URL 不变,但返回别的内容。redirect 发 301 / 302,URL 真的换。
  • rewrite 到 Cloud Function 能传 query 吗?: 能。query string 自动转发,** 匹配到的路径段通过 request URL 拿。
  • rewrite 的顺序重要吗?: 重要。Firebase 用第一条 source 匹配的规则。具体规则放通配规则前面。线上 rewrite 看起来「没生效」时,几乎都是顺序问题、或被一个同路径的静态文件挡住了——按rewrite 没触发逐项排查。
  • rewrite 部署成功了但函数返回 404 / “function not found”。: 这是函数区域 / 名称对不上,不是 rewrite 的 bug——参考Firebase function not found
  • 为什么 SPA rewrite 把我 sitemap 弄坏了?: 因为 ** 也匹配 /sitemap.xml。把通配范围缩窄,或在它前面加一条更具体的 /sitemap* 规则。

相关阅读

标签: #独立开发 #Firebase #部署 / 托管 #排查