firebase deploy --only hosting 跑到一半抛 HTTP Error: 400、Failed to make request to https://firebasehosting.googleapis.com/... 或 Site quota exceeded 这类错误——Firebase Hosting 的部署链路相对短,失败原因 90% 集中在 CLI 版本、auth token、firebase.json 配置和日配额这四件事上。本文按命中率列出 5 类常见原因,并给一条从 --debug 看完整日志、到逐项排查的修复路径。
常见原因
按命中率从高到低。
1. CLI 版本过旧或与项目不匹配
Firebase CLI 每隔几个月就改 API 协议,老版本(特别是 v11 以下)经常抛 Unexpected error: ... 或 Failed to parse host 之类含糊错误。
$ firebase --version
9.22.0 # 太老了,建议至少 13.x
如何判断:报错里出现 Cannot read property 'X' of undefined 或 Unexpected token in JSON、而你没改过任何配置——大概率 CLI 版本问题。
2. Auth token 过期或换了 Google 账号
CLI 在 ~/.config/configstore/firebase-tools.json 里存登录态,token 过期或你切到了别的 Google 账号时,会报 HTTP Error: 401, Request had invalid authentication credentials 或 Failed to authenticate, have you run firebase login?。
如何判断:firebase login:list 看当前登录的账号,是不是这个项目所属的那个。
3. firebase.json 的 public 路径和 build 产物对不上
public 字段指向被部署的目录。Astro 默认 build 到 dist/、Next.js 静态导出到 out/、Vite 到 dist/,但很多项目沿用了 firebase init 默认的 "public": "public",结果上传的是空目录。
// firebase.json — Astro 项目的典型配置
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [{ "source": "**", "destination": "/index.html" }]
}
}
如何判断:firebase deploy 日志显示 i hosting[project]: found 0 files in public——上传了 0 个文件。
4. 项目超出免费配额(Spark 计划)
Spark 计划每天每个 site 限 10GB 出站流量、每月 360MB 存储,部署时如果新构建产物把存储推过 10GB 累计上限,会报 Site quota exceeded 或 Hosting site is over its quota。
如何判断:Firebase Console → Hosting → Usage 标签,看 “Storage” 和 “Data transfer” 两个数字是否接近上限。
5. firebase.json 里 rewrites / redirects 语法错误
常见手写错误:source 和 destination 反了、glob 模式 ** 写成 *、redirects 的 type 不是 301/302。CLI 在部署时才校验,所以本地看着没问题。
// 错误示例:缺少必需的 type
"redirects": [
{ "source": "/old", "destination": "/new" }
]
// 正确
"redirects": [
{ "source": "/old", "destination": "/new", "type": 301 }
]
如何判断:日志里出现 Invalid hosting configuration 或 Specified "redirects" config is not valid。
最短修复路径
按”先拿完整日志、再排升级 / 重登 / 配置 / 配额”的顺序。
Step 1:用 --debug 重跑拿到完整堆栈
默认输出会折叠真正的报错。加上 --debug:
firebase deploy --only hosting --debug 2>&1 | tee firebase-deploy.log
日志里搜 [ERROR] 或 HTTP Error:,附近通常有真正的根因(PERMISSION_DENIED / INVALID_ARGUMENT / QUOTA_EXCEEDED 等)。
Step 2:升级 CLI 并重新登录
# 全局升级
npm install -g firebase-tools@latest
firebase --version # 期望 13.x 或更新
# 重新登录刷新 token
firebase logout
firebase login
# 确认当前登录账号
firebase login:list
firebase projects:list # 看是不是有这个 project_id
如果你在 CI 里部署,应该用 firebase login:ci 拿一个 token 存到环境变量 FIREBASE_TOKEN,而不是依赖交互式登录。
Step 3:校验 firebase.json 的 public 指向正确
# 看本地 build 产物
ls -la dist/ # 或 out/、build/、public/,看你的框架
# 看 firebase.json 里写的是什么
cat firebase.json | grep public
两者必须一致。常见框架对照:
| 框架 | build 输出目录 |
|---|---|
| Astro (static) | dist |
| Next.js (static export) | out |
| Vite | dist |
| Create React App | build |
| Vue CLI | dist |
也可以用 firebase deploy --only hosting --dry-run(如果 CLI 版本支持)只校验配置不真正上传。
Step 4:本地起 emulator 提前发现问题
firebase emulators:start --only hosting
# 在 http://localhost:5000 打开,跟生产行为一致
# rewrites / redirects 配置有问题 emulator 也会抛同样错误
修完配置在 emulator 验证通过,再 deploy。
Step 5:配额超限的应对
如果 Step 1 日志显示 QUOTA_EXCEEDED:
- Firebase Console → Hosting → Usage → 看当前数字。
- 临时方案:删除一些历史版本(Hosting → Release history → 点旧的 release → Delete)以释放存储。
- 长期方案:升级到 Blaze 按量付费计划(10GB 之后每 GB 约 $0.026 流量、$0.026 存储/月),不是真的”按月固定收费”,小站点几乎免费。
Step 6:rewrites / redirects 语法校验
把 firebase.json 贴进 hosting 配置 schema 比对字段名。或者本地用 npx ajv-cli 跑 JSON schema 校验:
npx ajv-cli validate \
-s https://raw.githubusercontent.com/firebase/firebase-tools/master/schema/firebase-config.json \
-d firebase.json
预防建议
- 在
package.json里 pin firebase-tools 版本("firebase-tools": "13.15.4")并加进 devDependencies,团队 / CI 永远用同一版。 - CI 用
firebase login:ci生成的 token 部署,避免 token 过期影响发版。 - 配置 GitHub Actions 在 PR 上跑
firebase hosting:channel:deploy preview预览部署,主分支合并前就能发现 firebase.json 问题。 - 部署前一步先跑
firebase emulators:exec "echo ok" --only hosting,配置错的话本地就 fail。 - Spark 配额监控:在 Firebase Console 里设置 Budget alert(哪怕没开 Blaze,也能在 80% 流量时邮件提醒)。