我的应用程序目前使用webpack,angular js和服务工作者.
使用sw-precache插件创建我的服务工作者.
https://www.npmjs.com/package/sw-precache-webpack-plugin
服务工作者缓存进展顺利,我可以看到我的静态资源是从chrome dev工具中的serviceworker.js中获取的.
现在,当我运行灯塔报告时,我仍然收到以下错误:
URL responds with a 200 when offline
https://github.com/GoogleChrome/lighthouse
在我开启离线时的Dev工具中,我实际上可以看到我的页面加载.某些第三方脚本的控制台中的某些错误失败.这是没有获得网址响应200的原因,因为我有来自第三方的一些控制台错误,即示例错误:
GET https://fonts.googleapis.com/css?family=Roboto+Slab:300,400,700 net::ERR_INTERNET_disCONNECTED
这次审计到底要找什么,我该如何实现?
编辑:当我离线打开时,我添加了网络选项卡的图片,因为我说页面加载正常.我注意到我的sw.js是从磁盘缓存加载的,我在其他网站上没有注意到,所以可能是那里的东西.
这里还有sw.js的内容
'use strict'; var precacheConfig = [["/css/app.styles.77e2a0c3e7ac001193566741984a07f0.css","77e2a0c3e7ac001193566741984a07f0"],["/css/vendor.styles.582e79ead0684a8fb648ce9e543ad810.css","582e79ead0684a8fb648ce9e543ad810"],["/favicon.ico","70ef569d9a12f6873e86ed57d575cf13"],["/fonts/MaterialIcons-Regular.eot","e79bfd88537def476913f3ed52f4f4b3"],["/fonts/MaterialIcons-Regular.svg","a1adea65594c502f9d9428f13ae210e1"],["/fonts/MaterialIcons-Regular.ttf","a37b0c01c0baf1888ca812cc0508f6e2"],["/fonts/MaterialIcons-Regular.woff","012cf6a10129e2275d79d6adac7f3b02"],["/fonts/MaterialIcons-Regular.woff2","570eb83859dc23dd0eec423a49e147fe"],["/icons/launcher-icon-2x.png","91896b953c39df7c40b4772100971220"],["/icons/launcher-icon-3x.png","0aee2add7f56559aeae9555e495c3881"],["/icons/launcher-icon-4x.png","b164109dd7640b14aaf076d55a0a637b"],["/images/aa_logo_only.png","b5b46a8c2ead9846df1f1d3035634310"],["/images/developer.png","e8df747b292fe6f5eb2403c7180c31da"],["/images/facebook.png","8ab42157d0974099a72e151c23073022"],["/images/home-bg.jpeg","0a0f7da8574b037463af2f1205801e56"],["/images/logo.png","e8712312e08ca427d79a9bf34aedd6fc"],["/images/map.png","af3443ef4ab2890cae371c7a3de437ed"],["/images/pattern.png","114d593511446b9a4c6e340f7fef5c84"],["/images/twitter.png","99da44949cd33e16d2d551d42559eaf2"],["/index.html","1e9b5c4b3abba7e13d8d28c98cfb3bb5"],["/js/app.d9ada27616bf469d794d.js","8e2fc74de7d5c122ab8f0aca7e31b075"],["/js/vendor.d9ada27616bf469d794d.js","3bbba4569b6f3b88881b0533260905fe"],["/manifest.json","4bea29155995b63a9f2855637c0fe74c"]]; var cacheName = 'sw-precache-v2-45-' + (self.registration ? self.registration.scope : ''); var ignoreUrlParametersMatching = [/^utm_/]; var addDirectoryIndex = function (originalUrl,index) { var url = new URL(originalUrl); if (url.pathname.slice(-1) === '/') { url.pathname += index; } return url.toString(); }; var createCacheKey = function (originalUrl,paramName,paramValue,dontCacheBustUrlsMatching) { // Create a new URL object to avoid modifying originalUrl. var url = new URL(originalUrl); // If dontCacheBustUrlsMatching is not set,or if we don't have a match,// then add in the extra cache-busting URL parameter. if (!dontCacheBustUrlsMatching || !(url.toString().match(dontCacheBustUrlsMatching))) { url.search += (url.search ? '&' : '') + encodeURIComponent(paramName) + '=' + encodeURIComponent(paramValue); } return url.toString(); }; var isPathWhitelisted = function (whitelist,absoluteUrlString) { // If the whitelist is empty,then consider all URLs to be whitelisted. if (whitelist.length === 0) { return true; } // Otherwise compare each path regex to the path of the URL passed in. var path = (new URL(absoluteUrlString)).pathname; return whitelist.some(function(whitelistedpathRegex) { return path.match(whitelistedpathRegex); }); }; var stripIgnoredUrlParameters = function (originalUrl,ignoreUrlParametersMatching) { var url = new URL(originalUrl); url.search = url.search.slice(1) // Exclude initial '?' .split('&') // Split into an array of 'key=value' strings .map(function(kv) { return kv.split('='); // Split each 'key=value' string into a [key,value] array }) .filter(function(kv) { return ignoreUrlParametersMatching.every(function(ignoredRegex) { return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes. }); }) .map(function(kv) { return kv.join('='); // Join each [key,value] array into a 'key=value' string }) .join('&'); // Join the array of 'key=value' strings into a string with '&' in between each return url.toString(); }; var hashParamName = '_sw-precache'; var urlsToCacheKeys = new Map( precacheConfig.map(function(item) { var relativeUrl = item[0]; var hash = item[1]; var absoluteUrl = new URL(relativeUrl,self.location); var cacheKey = createCacheKey(absoluteUrl,hashParamName,hash,false); return [absoluteUrl.toString(),cacheKey]; }) ); function setofCachedUrls(cache) { return cache.keys().then(function(requests) { return requests.map(function(request) { return request.url; }); }).then(function(urls) { return new Set(urls); }); } self.addEventListener('install',function(event) { event.waitUntil( caches.open(cacheName).then(function(cache) { return setofCachedUrls(cache).then(function(cachedUrls) { return Promise.all( Array.from(urlsToCacheKeys.values()).map(function(cacheKey) { // If we don't have a key matching url in the cache already,add it. if (!cachedUrls.has(cacheKey)) { return cache.add(new Request(cacheKey,{credentials: 'same-origin'})); } }) ); }); }).then(function() { // Force the SW to transition from installing -> active state return self.skipwaiting(); }) ); }); self.addEventListener('activate',function(event) { var setofExpectedUrls = new Set(urlsToCacheKeys.values()); event.waitUntil( caches.open(cacheName).then(function(cache) { return cache.keys().then(function(existingRequests) { return Promise.all( existingRequests.map(function(existingRequest) { if (!setofExpectedUrls.has(existingRequest.url)) { return cache.delete(existingRequest); } }) ); }); }).then(function() { return self.clients.claim(); }) ); }); self.addEventListener('fetch',function(event) { if (event.request.method === 'GET') { // Should we call event.respondWith() inside this fetch event handler? // This needs to be determined synchronously,which will give other fetch // handlers a chance to handle the request if need be. var shouldRespond; // First,remove all the ignored parameter and see if we have that URL // in our cache. If so,great! shouldRespond will be true. var url = stripIgnoredUrlParameters(event.request.url,ignoreUrlParametersMatching); shouldRespond = urlsToCacheKeys.has(url); // If shouldRespond is false,check again,this time with 'index.html' // (or whatever the directoryIndex option is set to) at the end. var directoryIndex = 'index.html'; if (!shouldRespond && directoryIndex) { url = addDirectoryIndex(url,directoryIndex); shouldRespond = urlsToCacheKeys.has(url); } // If shouldRespond is still false,check to see if this is a navigation // request,and if so,whether the URL matches navigateFallbackWhitelist. var navigateFallback = ''; if (!shouldRespond && navigateFallback && (event.request.mode === 'navigate') && isPathWhitelisted([],event.request.url)) { url = new URL(navigateFallback,self.location).toString(); shouldRespond = urlsToCacheKeys.has(url); } // If shouldRespond was set to true at any point,then call // event.respondWith(),using the appropriate cache key. if (shouldRespond) { event.respondWith( caches.open(cacheName).then(function(cache) { return cache.match(urlsToCacheKeys.get(url)).then(function(response) { if (response) { return response; } throw Error('The cached response that was expected is missing.'); }); }).catch(function(e) { // Fall back to just fetch()ing the request if some unexpected error // prevented the cached response from being valid. console.warn('Couldn\'t serve response for "%s" from cache: %O',event.request.url,e); return fetch(event.request); }) ); } } });