繁体   English   中英

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

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

Service Worker 未注册到由在 Firebase Functions 上运行的 Nuxt.js(通用)构建的应用程序。

我目前正在尝试使用 Nuxt.js 通用模式和 Firebase 函数构建原型 Web 应用程序。 该应用程序使用带有 nuxt 官方 pwa 模块的 service worker 来管理登录用户的会话,以便客户端可以将带有授权标头的请求发送到服务器,服务器将通过 Firebase 身份验证验证用户会话。

我已经尝试使用yarn run buildyarn run start在本地服务器上运行它,并确保 service worker 已正确注册并完美运行。 但是,当我尝试使用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.

我还发现 service worker 不会将会话数据发送到服务器。 当我使用firebase deploy源代码部署到生产中时,复制了完全相同的东西。

当我使用yarn create nuxt-appyarn run build和 firebase firebase serve完全清理项目时,它甚至会发生。 “sw.js”文件指示 Chrome 开发者工具上的失败状态。

我不确定它是否担心,但我的 Firebase 使用 Spark 计划。

我的项目树。

.
├── 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

源代码/静态/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')

函数/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)

预期行为是当我使用 firebase firebase servefirebase deploy运行应用程序时 sw.js 工作正常。

我设法找到了解决方案。 我可能误解了服务人员的行为。
我只是留下我的解决方案,以便我可以帮助有同样情况的人。

首先,我根本不知道 service worker js 文件/static/sw.js ,因为它是由yarn run build自动创建的,当我使用yarn run start运行应用程序时一切正常。 因此我认为我根本不必关心那个文件。

但是我发现/static目录中的所有文件都必须放在/public目录中,该目录将由 firebase 托管托管,以便客户端可以找到它们并下载它们。 我想当我使用yarn run start时, /static目录中的文件将由开发服务器托管。

我还意识到服务工作者是静态 javascript 文件,它们必须由 firebase 托管而不是由 firebase 函数托管。 我曾经尝试将它们放在dist/client中,但这没有任何意义。 它必须放在/public目录中。

我终于让它与以下项目树一起工作。 当我运行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

这是我的sw-firebase-auth.js (我用 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());
})

这也是nuxt.conf.js中的工作箱配置。 它与使用importScripts的官方 pwa-module 配合得很好。

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

我希望这会对某人有所帮助。

2020 年 6 月的 Nuxt.js 开发人员

如果您使用 SSR 部署 Nuxt.js 2.12.2 项目,您的项目目录中可能有.nuxt文件夹。 删除它,如果需要,从nuxt.config.js配置 Workbox 并运行nuxt buildnpm run buildyarn build

如果它在本地机器上工作,您可以尝试清除服务器上的缓存以确保所有旧的.nuxt文件夹都消失并重新部署项目。

希望这有帮助✨

暂无
暂无

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

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