Firebase route 404 常见原因

本地能开、部到 Firebase Hosting 就 404,用这套诊断流程加上 firebase.json 片段和 curl 命令快速定位原因。

本地跑得好好的。一部署,开线上 URL,礼貌地 404。Firebase Hosting 的 404 几乎都是四种原因之一,知道是哪种之后十分钟能修好——前提是你本地复现、对照 firebase.json、并真去看 build 产物。

问题背景

Firebase Hosting 从 firebase.json 配的 public 目录里找文件。请求进来先做文件匹配,再应用 cleanUrlstrailingSlash 转换,最后查 rewrite。都匹配不上就 404。“本地行线上不行”基本都是 build 产物和 Firebase 实际服务的内容之间有差。

判断标准

  • 部分路由能开部分 404——基本是 trailing slash / cleanUrls 不一致。
  • 只有 / 能开其它都 404——public 目录配错了。
  • 只有需要 SSR 的路由 404——缺一条 rewrite 到 Cloud Function 或 Cloud Run。
  • 只有今天新加的路由 404——build 没跑或者部署了旧产物。
  • /_astro/... 资源 404——build 产物里缺对应 hash 文件(缓存不匹配)。

快速结论

先用 firebase serve 本地复现一次。本地也复现,问题在 build;只有线上 404,问题在 firebase.json 或部署步骤。

开始前准备

  • firebase-tools 已装,能跑 firebase serve --only hosting
  • firebase.json 和 build 输出目录都能看到。
  • 失败 URL 用 curl 能稳定复现(排除浏览器缓存)。

实操步骤

  1. 本地复现。 一招就能定位 build 类问题:
npm run build
firebase serve --only hosting
# 另一个 shell:
curl -sI http://localhost:5000/about/ | head -3
# HTTP/1.1 404 ... ← build 输出问题
# HTTP/1.1 200 ... ← Firebase 配置 / 部署问题
  1. firebase.json 的 “public” 和真实 build 目录对得上。 Astro → dist,Next 静态 → out,Vite → dist
{
  "hosting": {
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "cleanUrls": true,
    "trailingSlash": true
  }
}

常见坑:framework 输出 dist/,但 public 还留着 firebase init 默认的 public/

  1. 确认 build 产物里真的有那个文件:
ls -la dist/about/
# index.html  ← 有
# (空)       ← framework 没生成该路由
find dist -name 'about*' -type f
# dist/about.html      ← 预期 cleanUrls: true
# dist/about/index.html ← 预期 trailingSlash: 'always'
  1. cleanUrlstrailingSlash 必须与 framework 一致。 四个合法组合:
framework 产出                          firebase.json
about.html                              cleanUrls: true,  trailingSlash: false  → /about
about.html + /about/ 跳转                cleanUrls: true,  trailingSlash: false  → /about
about/index.html                        cleanUrls: false, trailingSlash: true   → /about/
about/index.html                        cleanUrls: true,  trailingSlash: true   → /about/  (最干净)

Astro build.format: 'directory' 产出 about/index.html——firebase.json 里要 trailingSlash: true

  1. 该 SSR 的路由确认有 rewrite:
{
  "hosting": {
    "rewrites": [
      { "source": "/api/**", "function": "api" },
      { "source": "/render/**", "run": { "serviceId": "ssr-render", "region": "us-central1" } }
    ]
  }
}

rewrite 写了还 404(或 Function not found),说明函数名 / 区域和已部署函数对不上——firebase functions:list 查一下。

  1. 小心兜底 ** rewrite 到 /index.html——这会把所有 404 静默吃掉,每个 URL 返回首页 HTML:
{ "source": "**", "destination": "/index.html" }

Astro 和大多数静态 framework 不需要这条——内容站务必删掉。

  1. 确认 deploy 真的把新 build 推上去了:
firebase hosting:releases:list
# release   2026-05-22 14:02   <hash>   ← 时间戳对得上最近一次 build

curl -sI https://yourdomain.com/about/ | grep -i x-served-by
# 通常带 release hash 可对照
  1. 绕开缓存: 无痕窗口,或者 curl --header 'Cache-Control: no-cache'

执行检查清单

  • firebase serve 能复现同样的 404(或证明问题在平台侧)。
  • firebase.json 的 “public” 与 framework 实际输出目录一致。
  • cleanUrlstrailingSlash 与 framework 的文件命名匹配。
  • firebase.json 里没有遗留的 ** 兜底 rewrite。
  • CI 工作流先 npm run buildfirebase deploy

上线后验证

  • 之前 404 的所有 URL 都 curl -sI 返回 200。
  • Search Console URL Inspection 显示 “URL is on Google” 或至少 “Page fetched”。
  • 故意访问不存在路径仍然返回 404,不是 200(证明 404 页生效)。

容易踩的坑

  • public 指到源码目录——除了源码里有的路径全 404。
  • framework 和 host 的 trailing slash 不一致——页面在 /about/,但链接是 /about,一半能开一半不行。
  • 忘了自己加过 ** rewrite 到 /index.html——所有路由返回同一份 HTML(技术上不是 404 但效果一样)。
  • CI 里没 build 就 deploy。
  • CDN 缓存了旧的 404——清缓存或等待,文件其实在。
  • 需要登录态的路由对游客 404——确认该路由是否需要会话。

FAQ

  • / 能开 /about 404 为什么?: 十有八九是 trailing slash 或 cleanUrls。要么文件叫 about.html 但没开 cleanUrls,要么反过来。
  • 该开 cleanUrls 吗?: 大多数站建议开——URL 更干净。但内部链接要和这个设置保持一致。
  • 该 SSR 的路由 404 为什么?: Firebase Hosting 不会自动 SSR。需要加一条 rewrite 把该路径转到 Cloud Function 或 Cloud Run。firebase.json 里 rewrite 配了,但响应仍然是 404 或「function not found」,几乎都是函数名 / 区域和 rewrite 对不上(Firebase function not found)。
  • rewrite 看起来没问题但同一个 URL 仍然走静态文件。: 同路径有真实文件遮挡,或这条规则排在更宽泛的规则下面。按rewrite 没触发排查。
  • dist/ 里能看到文件,线上还 404?: 确认 deploy 真的上传了:firebase hosting:channel:list 看 release 内容。CI 可能没跑 build。

相关阅读

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