简体   繁体   English

使用 firebase 托管和功能的 Service Worker 注册失败

[英]Service Worker registration fails with firebase hosting and functions

Service Worker is not registered with an application builded by Nuxt.js (Universal) which is running on Firebase Functions. Service Worker 未注册到由在 Firebase Functions 上运行的 Nuxt.js(通用)构建的应用程序。

I'm currently trying to build a prototype web application with Nuxt.js Universal mode and Firebase Functions.我目前正在尝试使用 Nuxt.js 通用模式和 Firebase 函数构建原型 Web 应用程序。 The app uses service worker with nuxt official pwa-module to manage the session of logged in user, so that the client could send the request with authorization header to the server and server would verify the user session via Firebase Authentication.该应用程序使用带有 nuxt 官方 pwa 模块的 service worker 来管理登录用户的会话,以便客户端可以将带有授权标头的请求发送到服务器,服务器将通过 Firebase 身份验证验证用户会话。

I've already tried to run it on local server with yarn run build and yarn run start , and ensured the service worker have been correctly registered and worked perfectly.我已经尝试使用yarn run buildyarn run start在本地服务器上运行它,并确保 service worker 已正确注册并完美运行。 However when I try to check the same operation with firebase serve , I receive following errors on the browser.但是,当我尝试使用firebase serve检查相同的操作时,我在浏览器上收到以下错误。

A bad HTTP response code (404) was received when fetching the script.
Failed to load resource: net::ERR_INVALID_RESPONSE
dcbac67bb39a765db27a.js:1 Service worker registration failed: TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.

I also found that the service worker does not send the session data to the server.我还发现 service worker 不会将会话数据发送到服务器。 Exactly same thing was reproduced when I deployed source into production with firebase deploy .当我使用firebase deploy源代码部署到生产中时,复制了完全相同的东西。

It even occurs when I completely clean project with yarn create nuxt-app , yarn run build and firebase serve .当我使用yarn create nuxt-appyarn run build和 firebase firebase serve完全清理项目时,它甚至会发生。 "sw.js" file indicates failed status on Chrome developer tool. “sw.js”文件指示 Chrome 开发者工具上的失败状态。

I'm not sure if it is concerned but my Firebase is on Spark plan.我不确定它是否担心,但我的 Firebase 使用 Spark 计划。

My project tree.我的项目树。

.
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── functions
│   ├── index.js
│   ├── nuxt
│   │   ├── App.js
│   │   ├── axios.js
│   │   ├── client.js
│   │   ├── components
│   │   ├── dist
│   │   ├── empty.js
│   │   ├── index.js
│   │   ├── loading.html
│   │   ├── middleware.js
│   │   ├── router.js
│   │   ├── server.js
│   │   ├── store.js
│   │   ├── sw.plugin.js
│   │   ├── sw.template.js
│   │   ├── utils.js
│   │   └── views
│   ├── package-lock.json
│   ├── package.json
│   └── yarn.lock
├── public
└── src
    ├── assets
    ├── components
    ├── jest.config.js
    ├── layouts
    ├── middleware
    ├── nuxt.config.js
    ├── package.json
    ├── pages
    ├── plugins
    ├── server
    ├── static
    │   └── sw.js
    ├── store
    └── test
    └── yarn.lock

src/static/sw.js源代码/静态/sw.js

importScripts('/_nuxt/workbox.4c4f5ca6.js')

workbox.precaching.precacheAndRoute([
  {
    "url": "/_nuxt/021e1640b53136b75c48.js",
    "revision": "2753e747206d803c793b59a324c1931b"
  },
  {
    "url": "/_nuxt/03c9e340d8692d1403a9.js",
    "revision": "2b882d73d20a0b2cfd318e9e05d3496e"
  },
  {
    "url": "/_nuxt/78bddfa6b6a4919b78d6.js",
    "revision": "70312f6623089e3b4aa6454120c1e177"
  },
  {
    "url": "/_nuxt/85c817abccdd40162004.js",
    "revision": "45448f8709d01af59bb125a1d06be23a"
  },
  {
    "url": "/_nuxt/8654a518d0f3e326c9a6.js",
    "revision": "a42426f5e7b458acc6fdf0e9e48c7d35"
  },
  {
    "url": "/_nuxt/95b421159066eff9e318.js",
    "revision": "efd1643042f804defa7212979867558a"
  },
  {
    "url": "/_nuxt/9b487bf2df1190b68565.js",
    "revision": "78837d0e624deccc85761b44f9ede9be"
  },
  {
    "url": "/_nuxt/ce59381752309c170d41.js",
    "revision": "d3e50bf27891c4efa6dff5076a0772a6"
  },
  {
    "url": "/_nuxt/d8fa6ae5ca14331879f6.js",
    "revision": "5da6698c9359df803243ecc44519b610"
  },
  {
    "url": "/_nuxt/dcbac67bb39a765db27a.js",
    "revision": "9505aa84ddb2a70b826d324433daff36"
  },
  {
    "url": "/_nuxt/dee89eef613849499c7f.js",
    "revision": "43117ed819efe3d00c963dd655894d5f"
  }
], {
  "cacheId": "justtest",
  "directoryIndex": "/",
  "cleanUrls": false
})

workbox.clientsClaim()
workbox.skipWaiting()

workbox.routing.registerRoute(new RegExp('/_nuxt/.*'), workbox.strategies.cacheFirst({}), 'GET')

workbox.routing.registerRoute(new RegExp('/.*'), workbox.strategies.networkFirst({}), 'GET')

functions/index.js函数/index.js

const functions = require("firebase-functions")
const { Nuxt } = require("nuxt")
const express = require("express")
const app = express()

const nuxt = new Nuxt({ buildDir: "nuxt", dev: false })

function handleRequest(req, res) {
  res.setHeader('Cache-Control', 'private')
  return new Promise((resolve, reject) => {
    nuxt.render(req, res, promise => {
      promise.then(resolve).catch(reject)
    })
  })
}

app.use(handleRequest)

exports.ssr = functions.https.onRequest(app)

Expected behavior is that sw.js working fine when I run the app with firebase serve and firebase deploy .预期行为是当我使用 firebase firebase servefirebase deploy运行应用程序时 sw.js 工作正常。

I managed to find the solution.我设法找到了解决方案。 I may have misunderstood the behavior of service workers.我可能误解了服务人员的行为。
I just leave my solution so that I could help somebody who has the same situation.我只是留下我的解决方案,以便我可以帮助有同样情况的人。

First of all, I was not aware of the service worker js file /static/sw.js at all since it is automatically created by yarn run build and everything worked fine when I run the app with yarn run start .首先,我根本不知道 service worker js 文件/static/sw.js ,因为它是由yarn run build自动创建的,当我使用yarn run start运行应用程序时一切正常。 Therefore I thought I wouldn't have to care about that file at all.因此我认为我根本不必关心那个文件。

However I found out that all the files in /static directory have to be placed in /public directory, which will be hosted by firebase hosting, so that clients can find them and download them.但是我发现/static目录中的所有文件都必须放在/public目录中,该目录将由 firebase 托管托管,以便客户端可以找到它们并下载它们。 I guess when I use yarn run start the files in /static directory would be hosted by dev server.我想当我使用yarn run start时, /static目录中的文件将由开发服务器托管。

Also I realized that the service workers are static javascript files and they have to be hosted by firebase hosting, not by firebase functions.我还意识到服务工作者是静态 javascript 文件,它们必须由 firebase 托管而不是由 firebase 函数托管。 I once tried to place them in dist/client but it doesn't make any sense.我曾经尝试将它们放在dist/client中,但这没有任何意义。 It has to be placed in /public directory.它必须放在/public目录中。

I finally make it work with following project tree.我终于让它与以下项目树一起工作。 When I run yarn run build I copy all the contents in /src/static to /public to host them with firebase hosting.当我运行yarn run build时,我将/src/static中的所有内容复制到/public以使用 firebase 托管来托管它们。

.
├── firebase.json
├── functions
│   ├── index.js
│   ├── nuxt
│   │   ├── App.js
│   │   ├── axios.js
│   │   ├── client.js
│   │   ├── components
│   │   ├── dist
│   │   ├── empty.js
│   │   ├── index.js
│   │   ├── loading.html
│   │   ├── middleware.js
│   │   ├── router.js
│   │   ├── server.js
│   │   ├── store.js
│   │   ├── sw.plugin.js
│   │   ├── sw.template.js
│   │   ├── utils.js
│   │   └── views
│   ├── package-lock.json
│   ├── package.json
│   └── yarn.lock
├── public
│   ├── favicon.ico
│   ├── sw-firebase-auth.js
│   └── sw.js
└── src
    ├── assets
    ├── components
    ├── layouts
    ├── middleware
    ├── nuxt.config.js
    ├── package.json
    ├── pages
    ├── plugins
    ├── server
    ├── static
    │   ├── favicon.ico
    │   ├── sw-firebase-auth.js
    │   └── sw.js
    ├── store
    └── yarn.lock

This is my sw-firebase-auth.js .这是我的sw-firebase-auth.js (I compile this script with Browserify to work.) (我用 Browserify 编译这个脚本来工作。)

var firebase = require('firebase')

// Initialize the Firebase app in the service worker script.
firebase.initializeApp({
  apiKey: '*************',
  authDomain: '*************',
  databaseURL: '*************',
  projectId: '*************',
  storageBucket: '*************',
  messagingSenderId: '*************'
})

/**
 * Returns a promise that resolves with an ID token if available.
 * @return {!Promise<?string>} The promise that resolves with an ID token if
 *     available. Otherwise, the promise resolves with null.
 */
const getIdToken = () => {
  return new Promise((resolve) => {
    const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
      unsubscribe();
      if (user) {
        user.getIdToken().then((idToken) => {
          resolve(idToken)
        }, () => {
          resolve(null)
        });
      } else {
        resolve(null)
      }
    })
  })
}

const getOriginFromUrl = (url) => {
  const pathArray = url.split('/');
  const protocol = pathArray[0];
  const host = pathArray[2];
  return protocol + '//' + host;
};

self.addEventListener('fetch', (event) => {
  const requestProcessor = (idToken) => {
    let req = event.request;
    if (self.location.origin == getOriginFromUrl(event.request.url) &&
        (self.location.protocol == 'https:' ||
         self.location.hostname == 'localhost') &&
        idToken) {
      const headers = new Headers();
      for (let entry of req.headers.entries()) {
        headers.append(entry[0], entry[1]);
      }
      headers.append('Authorization', 'Bearer ' + idToken);
      try {
        req = new Request(req.url, {
          method: req.method,
          headers: headers,
          mode: 'same-origin',
          credentials: req.credentials,
          cache: req.cache,
          redirect: req.redirect,
          referrer: req.referrer,
          body: req.body,
          bodyUsed: req.bodyUsed,
          context: req.context
        });
      } catch (e) {
        console.log(e)
      }
    }
    return fetch(req);
  };
  event.respondWith(getIdToken().then(requestProcessor, requestProcessor));
});

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
})

Also this is workbox config in nuxt.conf.js .这也是nuxt.conf.js中的工作箱配置。 It works well with official pwa-module using importScripts .它与使用importScripts的官方 pwa-module 配合得很好。

  workbox: {
    importScripts: [
      'sw-firebase-auth.js'
    ]
  }

I hope this would help somebody.我希望这会对某人有所帮助。

Fellow Nuxt.js developers in 2020, Jun 2020 年 6 月的 Nuxt.js 开发人员

If you are deploying Nuxt.js 2.12.2 project with SSR, you probably have .nuxt folder in your project directory.如果您使用 SSR 部署 Nuxt.js 2.12.2 项目,您的项目目录中可能有.nuxt文件夹。 Delete that, configure Workbox from nuxt.config.js if you need and run nuxt build , npm run build or yarn build .删除它,如果需要,从nuxt.config.js配置 Workbox 并运行nuxt buildnpm run buildyarn build

If it works on local machine, you can try clearing caches on server to make sure all old .nuxt folders are gone and redeploy the project.如果它在本地机器上工作,您可以尝试清除服务器上的缓存以确保所有旧的.nuxt文件夹都消失并重新部署项目。

Hope this helps ✨希望这有帮助✨

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM