You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django+React集成Firebase推送通知:ServiceWorker注册失败解决

问题描述

我开发的Web应用采用Django Rest Framework后端+React前端架构,集成Firebase推送通知服务时遇到生产环境异常:

开发环境下(React运行于localhost:3000,Django运行于127.0.0.1:8000)能正常生成FCM令牌并接收通知,但生产环境中用npm run build构建React后由Django托管时,出现以下错误:

FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('https://mywebsite.in/firebase-cloud-messaging-push-scope') with script ('https://mywebsite.in/firebase-messaging-sw.js'): The script has an unsupported MIME type ('text/html'). (messaging/failed-service-worker-registration).
    at registerDefaultSw.ts:43:25
    at p (regeneratorRuntime.js:44:17)
    at Generator.<anonymous> (regeneratorRuntime.js:125:22)
    at Generator.throw (regeneratorRuntime.js:69:21)
    at Td (asyncToGenerator.js:3:20)
    at s (asyncToGenerator.js:25:9)

我的Firebase相关配置文件如下:

firebase-messaging-sw.js(React public目录)

importScripts(
  "https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js"
);
importScripts(
  "https://www.gstatic.com/firebasejs/9.0.0/firebase-messaging-compat.js"
);

const firebaseConfig = {
  ...
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.icon,
  };

  console.log(notificationOptions, notificationTitle);

  self.registration.showNotification(notificationTitle, notificationOptions);
});

}); // 注意:此处存在多余的闭合括号,会导致脚本语法错误

firebase.js(React src目录)

import { initializeApp } from "firebase/app";
import { getMessaging } from "firebase/messaging";

const firebaseConfig = {
...
};

export const app = initializeApp(firebaseConfig);
export const messaging = getMessaging(app);

FCM令牌生成代码

const requestPermission = async () => {
    if (Notification.permission === "default") {
      if (user.regd_as === "TCH") {
        NotificationBar(
          `Please click allow for notification accesss so that you can receive notifications when students send you a request.`,
          `info`
        );
      } else {
        NotificationBar(
          `Please click allow for notification accesss so that you can receive notifications when teacher accept your request.`,
          `info`
        );
      }
    }
    try {
      const permission = await Notification.requestPermission();

      if (permission === "granted") {
        // Generate token
        const token = await getToken(messaging, {
          vapidKey:
            "BJueTNhdRYtjQJ3BqwytPu4MUkK0BrUkuPcnDd3oBCoppBTb-xdJtaRcmu9CLStX6UeltYst--YtMirduz3vGJI",
        });
        if (token) {
          console.log(token);
          let response = await storeNotificationToken(token);
        } else {
          console.log(`token was not produced`);
        }
      } else if (permission === "denied") {
        if (localStorage.getItem("noti_denied_seen") === "true") {
          return;
        }
        if (user.regd_as === "TCH") {
          NotificationBar(
            `Since you have denied notification permission you will miss out notifications when students send you request. Please enable/ allow notification access.`,
            `error`
          );
        } else {
          NotificationBar(
            `Since you have denied notification permission you will miss out notifications when teachers aceepts your request. Please enable/ allow notification access.`,
            `error`
          );
        }

        localStorage.setItem("noti_denied_seen", "true");
      }
    } catch (error) {
      console.log(error);
    }
  };

  // 获取用户通知权限
  useEffect(() => {
    requestPermission();
  }, []);

解决方案

错误核心原因是Django返回firebase-messaging-sw.js时使用了text/html MIME类型,而ServiceWorker要求必须以application/javascript类型返回。同时需修正脚本语法错误、确保文件路径可访问。

步骤1:修复ServiceWorker脚本语法错误

删除firebase-messaging-sw.js末尾多余的});,修正后文件结尾应为:

messaging.onBackgroundMessage((payload) => {
  // 原有逻辑代码
});
// 移除最后多余的闭合括号

步骤2:确保ServiceWorker文件在Django静态资源目录中

  • 执行npm run build后,React会将public目录下的文件复制到build目录根目录
  • 将build目录内的所有文件复制到Django项目的静态资源目录(如myproject/static/react_build/),或直接配置Django将React的build目录作为静态资源根路径

步骤3:配置Django返回正确的MIME类型

方法A:单独映射ServiceWorker路由

在项目根urls.py中添加:

from django.http import FileResponse
from django.conf import settings
import os

def serve_firebase_sw(request):
    # 根据实际静态资源路径调整
    sw_path = os.path.join(settings.STATIC_ROOT, 'firebase-messaging-sw.js')
    return FileResponse(open(sw_path, 'rb'), content_type='application/javascript')

urlpatterns = [
    # 其他已有路由
    path('firebase-messaging-sw.js', serve_firebase_sw),
]

方法B:全局配置JS文件MIME类型

在settings.py中添加:

import mimetypes
mimetypes.add_type("application/javascript", ".js", True)

此方法会确保所有.js文件都以正确的MIME类型返回,无需单独配置单个文件。

步骤4:显式注册ServiceWorker(可选但更可靠)

默认Firebase会自动注册ServiceWorker,但在Django托管场景下,显式注册可避免路径问题。修改firebase.js:

import { initializeApp } from "firebase/app";
import { getMessaging } from "firebase/messaging";

const firebaseConfig = {
  ...
};

export const app = initializeApp(firebaseConfig);
export const messaging = getMessaging(app);

// 显式注册ServiceWorker
export const registerSw = async () => {
  if ('serviceWorker' in navigator) {
    try {
      const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
      console.log('Service Worker 注册成功:', registration);
      await messaging.useServiceWorker(registration);
    } catch (error) {
      console.error('Service Worker 注册失败:', error);
    }
  }
};

然后在获取权限前先执行注册:

useEffect(() => {
  registerSw().then(() => {
    requestPermission();
  });
}, []);

步骤5:验证配置

  1. 部署修改后的代码到生产环境
  2. 访问https://yourdomain.in/firebase-messaging-sw.js,检查响应头的Content-Type是否为application/javascript
  3. 打开浏览器控制台,确认ServiceWorker注册成功且无错误提示

内容的提问来源于stack exchange,提问作者Ritankar Bhattacharjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 00:44:59