Service Worker registration error: Unsupported MIME type ('text/html')

Service Worker registration error: Unsupported MIME type ('text/html')

我正在使用 create-react-app with an express 服务器。

create-react-app 有一个缓存本地资产 (https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app) 的 pre-configured ServiceWorker。

我尝试在我的服务器上发布时遇到的问题是 service-worker.js 文件可用,但当我尝试注册它时我的浏览器控制台出现错误。

在 Firefox 上,我收到此错误:

Error during service worker registration:

TypeError: ServiceWorker script at https://my-domain.com/service-worker.js for scope https://my-domain.com/ encountered an error during installation.

在 Chrome,我得到了更具描述性的错误:

Error during service worker registration: DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').

果然,如果我查看我的开发人员工具的网络选项卡并搜索 service-worker.js 文件,我可以看到它在 HTTP headers 中有错误的 MIME 类型。

虽然我不明白,为什么它的 MIME 类型错误?

在我的 Express 服务器应用程序中,我有一个重定向到 index.html:

的通配符(星号/*)路由
// Load React App
// Serve HTML file for production
if (env.name === "production") {
  app.get("*", function response(req, res) {
    res.sendFile(path.join(__dirname, "public", "index.html"));
  });
}

这是一种非常常见的设计模式。但是,这意味着任何对未知文本文件的请求最初都会被重定向到 index.html,因此 return 的 MIME 类型为 "text/html",即使它实际上是 JavaScript 或SVG 或其他类型的纯文本文件。

我找到的解决方案是在通配符路由之前为service-worker.js添加特定路由:

app.get("/service-worker.js", (req, res) => {
  res.sendFile(path.resolve(__dirname, "public", "service-worker.js"));
});
app.get("*", function response(req, res) {
  res.sendFile(path.join(__dirname, "public", "index.html"));
});

现在,当浏览器查找 service-worker.js 时,Express 会 return 使用正确的 MIME 类型。

(请注意,如果您尝试在通配符后添加 service-worker.js 路由,它不会起作用,因为通配符路由将被覆盖。)

ServiceWorker 支持的 MIME 类型是 'text/javascript'、application/javascript 和 application/x-javascript。转到您的服务器文件并设置

    response.writeHead(201, {
        'Content-Type': 'application/javascript'
    });

该脚本具有不受支持的 MIME 类型 ('text/html')。 无法加载资源:net::ERR_INSECURE_RESPONSE (索引):1 未捕获(承诺)DOMException:无法注册 ServiceWorker:脚本具有不受支持的 MIME 类型('text/html')。

template.js 根文件

的代码
export default ({ markup, css }) => {
  return `<!doctype html>
      <html lang="en">
        <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>MERN Marketplace</title>
          <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400">
          <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

          <style>
              a{
                text-decoration: none
              }
          </style>
          <link rel="manifest" href="./manifest.json">
        </head>
        <body style="margin:0">
            <div id="root">${markup}</div>
          <style id="jss-server-side">${css}</style>
          <script type="text/javascript" src="/dist/bundle.js"></script>
          <script>
          if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('/sw.js').then(function() { 
              console.log("Service Worker Registered"); 
            });
          }
          </script>
        </body>
      </html>`;
};

应用此更改:

'/service-worker.js'  // ❌
'./service-worker.js' // ✅

解决了我的问题。

(在navigator.serviceWorker.register('/service-worker.js'))


或者您可能需要:

'%PUBLIC_URL%/serviceworker.js'

感谢@DanielLord for

反应: public/index.html

<script> 
  if ('serviceWorker' in navigator) {
    window.addEventListener('sw-cached-site.js', function() {
      navigator.serviceWorker.register('service-worker.js', {
        scope: '/',
      });
    });
  } 
  window.process = { env: { NODE_ENV: 'production' } };
</script>

注:满app/site public/sw-cached-site.js

const cacheName = 'v1';
self.addEventListener('activate', (e) =>{
  e.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cache => {
          if(cache !== cacheName) { 
            return caches.delete(cache);
          }
        })
      )
    })
  )
});
self.addEventListener('fetch', e => { 
  e.respondWith(
      fetch(e.request)
        .then(res => {
            const resClone = res.clone();
            caches
                .open(cacheName)
                .then(cache => {
                    cache.put(e.request, resClone);
                }); 
                return res;
        }).catch(err => caches.match(e.request).then(res => res))
  );
});

确保已生成服务工作者文件(Chrome DevTools -> Sources -> Filesystem)。如果根本没有生成 service worker 文件(检查你的部署脚本),你可能会收到这样的错误。

如果您正在使用 NodeJS,serviceWorker 文件应放在 public 文件夹中。 如果您使用 Webpack 将 serviceWorker 导出到 public,则需要使用 'copy-webpack-plugin'.

我使用 nginx 为 React 应用程序提供服务,我解决了这个问题,将 mime 类型添加到 nginx:

http {
    include    mime.types; // <--- this line

    # another config details
}

你还可以找到mime.types file here

我遇到了同样的问题,从我的配置中删除其他 firebase 库为我解决了这个问题 Check this on Github


// Change this 
var firebaseConfig = {
    apiKey: "*********",
    authDomain: "**********",
    databaseURL: "*********",
    projectId: "***********",
    storageBucket: "************",
    messagingSenderId: "***********",
    appId: "************"
};

// To =>
var firebaseConfig = {
  apiKey: "*****************",
  projectId: "**********",
  messagingSenderId: "*******",
  appId: "***********"
};

我认为 http://localhost:3000/service-worker.js 中不存在服务工作者文件,因此服务器返回 index.html。然后注册功能不知道如何处理 index.html 文件并告诉您 MIME 类型不正确。

一个快速修复方法是将 service-worker.js 文件复制到 public 文件夹,这样当您点击 http://localhost:3000/service-worker.js 时,您就可以在浏览器中看到该文件。

记得转到 ChromeDev > Applications > ServiceWorkers 并点击取消订阅。为了删除错误的。记住还要禁用缓存

就我而言,对于 Vue,我需要使用 command-line 工具在 public 目录中生成 mockServiceWorker.js,如下所述:

https://mswjs.io/docs/getting-started/integrate/browser

我从样本中不清楚这一点。具体到 运行 的 CLI 命令是:

npx msw init ./public
self.addEventListener('fetch', function(event) {});

在您的 service-worker.js 文件中添加以上代码

当 运行 webpack 开发服务器时,它会为缺少的资源呈现默认值 index.html。

如果您使用浏览器加载 http://localhost:3000/sw.js,您实际上会看到一个呈现的 React 应用程序(由 index.html 启动)。这就是为什么 mime 类型是 html,而不是 javascript。

此回退到 index.html 旨在支持 SPA 和前端路由。例如 /product/123/reviews 在后端没有这样的 html 文件,JS SPA 应用程序在前端处理它。

为什么您的文件丢失了?我猜你在项目的根文件夹中创建了那个文件。

Webpack 开发服务器不从该根文件夹提供服务。

将您的 sw.js 移动到项目的 public/ 文件夹中,它将按预期提供。

我想,service worker 文件应该在根路径上。在我的例子中,我不能使用根路径,所以我使用 apache 重定向规则将 service-worker.js 重定向到我的子路径。

 RewriteRule "^/service-worker.js$"  "/sub/service-worker.js"

我在使用 python 托管网站时遇到了类似的问题。 None 这里的解决方案对我有用,我遇到了一个 bug posted in chrome dev forum,它设法解决了我的问题。显然,在我的案例中这是 windows 相关的问题,因为 .js 文件的注册表条目的内容类型设置为 text/plain 由于某些先前的配置,我不得不改回 application/javascript。

TLDR:

  1. 打开注册表编辑器
  2. 转到Computer\HKEY_CLASSES_ROOT\.js
  3. 将内容类型更改为 application/javascript
  4. 重新启动 Chrome 和 运行 您的网站

希望这对某些 none 以上作品有所帮助。

此错误是因为应用程序(在本例中为 Angular)未找到文件 service-worker.jsngsw-config.js 或其他名称文件)。

我通过添加 angular.json:

解决了这个问题
"serviceWorker": true,
"ngswConfigPath": "service-worker.json",

这应该添加到所有配置:例如,生产、测试​​和暂存。