Firebase模拟器需混用localhost与127.0.0.1才能运行的原因排查
问题背景
在Node.js项目中使用Firebase模拟器本地测试时,必须混用localhost和127.0.0.1作为主机地址才能正常运行,具体现象如下:
初始化Firebase Admin的代码:
app = admin.initializeApp({ projectId: projectId, databaseURL: `${process.env.FIREBASE_DATABASE_EMULATOR_HOST}?ns=${projectId}`, authDomain: `${process.env.FIREBASE_AUTH_EMULATOR_HOST}?ns=${projectId}` })
测试场景:
- 全用localhost:Auth模拟器报错
Error: Error while making request: connect ECONNREFUSED ::1:9099 - 全用127.0.0.1:Realtime Database访问时报错
TypeError [ERR_INVALID_URL]: Invalid URL - 混用(Database用localhost,Auth用127.0.0.1):所有功能正常
环境信息:firebase-admin v10.3.0,Mac Studio M1(macOS Ventura 13.0.1),Node.js 18.12.1
原因分析
1. Auth模拟器localhost连接失败
Node.js 18及以上版本在M1 Mac上解析localhost时,默认优先返回IPv6地址(::1)。但对应版本的Firebase Auth模拟器仅绑定了IPv4的127.0.0.1接口,未监听IPv6地址,导致Node.js尝试连接::1:9099时被拒绝。改用127.0.0.1会强制Node.js使用IPv4协议连接,避开IPv6监听缺失的问题。
2. Realtime Database 127.0.0.1 URL无效
你的初始化代码中databaseURL未添加HTTP协议前缀(http://)。firebase-admin v10.3.0的内部逻辑对localhost做了特殊处理,会自动补全协议生成合法URL;但对于127.0.0.1,该自动补全逻辑未触发,导致生成的URL(如127.0.0.1:9000?ns=xxx)因缺少协议头被Node.js判定为无效。
解决方案
方案1:统一添加协议前缀
修改初始化代码,给模拟器地址加上http://前缀,这样无论使用localhost还是127.0.0.1都能正常工作:
app = admin.initializeApp({ projectId: projectId, databaseURL: `http://${process.env.FIREBASE_DATABASE_EMULATOR_HOST}?ns=${projectId}`, authDomain: `http://${process.env.FIREBASE_AUTH_EMULATOR_HOST}?ns=${projectId}` })
方案2:强制Node.js优先使用IPv4
启动Node项目时添加--dns-result-order=ipv4first参数,让localhost解析时优先返回IPv4地址,这样Auth模拟器也可以用localhost:
node --dns-result-order=ipv4first your-app-entry-file.js
内容的提问来源于stack exchange,提问作者Joris

