Angular构建的PWA集成Firebase Cloud Messaging时Service Worker报错问询
ERROR Error: Uncaught (in promise): FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:18080/firebase-cloud-messaging-push-scope') with script ('http://localhost:18080/firebase-messaging-sw.js'): A bad HTTP response code (404) was received when fetching the script. (messaging/failed-service-worker-registration). FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:18080/firebase-cloud-messaging-push-scope') with script ('http://localhost:18080/firebase-messaging-sw.js'): A bad HTTP response code (404) was received when fetching the script. (messaging/failed-service-worker-registration).
这个报错是Firebase Cloud Messaging SDK的默认逻辑触发的:初始化时如果没有手动指定已注册的Service Worker实例,SDK会自动请求站点根目录下的firebase-messaging-sw.js文件并尝试注册专属SW,这个文件缺失就会返回404错误。
你现在能正常通过getToken()获取token,是因为新版FCM SDK在未找到专属SW时,会暂时调用浏览器原生的推送订阅能力生成token,仅能支持应用在前台打开状态下的推送接收,后台/离线状态下的推送接收、系统通知弹出功能会失效,所以才会出现能拿token但控制台报SW相关错误的情况。
- 是否必须额外添加
firebase-messaging-sw.js文件:分场景判断。如果仅需要应用前台运行时接收推送,可以不用添加,只需要在FCM初始化时手动传入Angular自带的Service Worker注册实例即可。如果需要后台、离线状态下也能正常接收推送、弹出系统通知,就必须添加该SW文件,或者将FCM的SW逻辑合并到现有Angular SW中。 firebase-messaging-sw.js的作用:是FCM官方封装的专属Service Worker脚本,专门处理推送生命周期逻辑,包括后台/离线推送的接收、系统通知的渲染弹出、通知点击事件的响应、FCM订阅数据的同步更新等。- 与Angular自带Service Worker的协同规则:浏览器原生支持同域下注册多个Service Worker,二者默认scope不重叠(FCM SW默认scope为
/firebase-cloud-messaging-push-scope,Angular SW默认scope为站点根目录/),功能互不冲突,会分别处理各自负责的逻辑。如果需要合并为一个SW,也可以直接将FCM的SW逻辑导入到你自定义的Angular SW入口文件中。
2024年FCM没有发布强制要求调整Service Worker配置的规则更新,你这个问题是代码迁移导致的配置丢失:
- 大概率是迁移前的FCM初始化逻辑手动传入了已注册的Angular SW实例,不会触发SDK自动查找
firebase-messaging-sw.js的逻辑,迁移过程中这个配置被遗漏,SDK就走默认逻辑请求缺失的SW文件,触发404报错。 - 小概率是之前的打包配置会把
firebase-messaging-sw.js打包到输出目录,后续调整构建配置时移除了该文件的assets配置,导致部署后文件缺失。
- 不需要后台推送的修复方式:在调用
getToken前手动获取Angular SW的注册实例传入即可,示例代码:
import { getMessaging, getToken } from "firebase/messaging"; // 先获取Angular默认注册的根scope SW实例 navigator.serviceWorker.getRegistration('/') .then(swReg => { const messaging = getMessaging(/* 你的Firebase app实例 */); getToken(messaging, { vapidKey: '你的VAPID公钥', // 手动传入SW实例,禁用SDK自动注册专属SW的逻辑 serviceWorkerRegistration: swReg }).then(currentToken => { // 原有获取token的逻辑 }) })
- 需要后台推送的修复方式:
- 在项目
src目录下创建firebase-messaging-sw.js文件,写入FCM基础SW逻辑 - 打开
angular.json,找到对应项目的build配置,在assets数组中添加该文件的打包规则,确保构建后文件会输出到dist根目录:
"assets": [ "src/favicon.ico", "src/assets", "src/manifest.webmanifest", "src/firebase-messaging-sw.js" ] - 在项目
内容的提问来源于stack exchange,提问作者SNnaKR

