Почему 404.html вызывает неперехваченную ошибку во время кэширования работника службы?

Я внедрил сервисного работника в свое веб-приложение и попытался кэшировать все html, css, js и файлы изображений. Мой хостинг - firebase, после успешного развертывания я проверил, будет ли сервис работать и файлы будут кэшироваться, к сожалению, произойдет следующая ошибка.

Uncaught (в обещании) TypeError: Запрос не выполнен

сервис-worker.js

let cacheName = 'my-tools-v1';
let filesToCache = [
    '/',
    '/css/app.css',
    '/css/diffview.css',
    '/css/json-lint.css',
    '/css/materialize.css',
    '/images/favicon.png',
    '/images/icons/apple-touch-icon.png',
    '/images/icons/apple-touch-icon-57x57.png',
    '/images/icons/apple-touch-icon-72x72.png',
    '/images/icons/apple-touch-icon-76x76.png',
    '/images/icons/apple-touch-icon-114x114.png',
    '/images/icons/apple-touch-icon-120x120.png',
    '/images/icons/apple-touch-icon-144x144.png',
    '/images/icons/apple-touch-icon-152x152.png',
    '/images/icons/apple-touch-icon-180x180.png',
    '/images/icons/icon-72x72.png',
    '/images/icons/icon-96x96.png',
    '/images/icons/icon-128x128.png',
    '/images/icons/icon-144x144.png',
    '/images/icons/icon-152x152.png',
    '/images/icons/icon-192x192.png',
    '/images/icons/icon-384x384.png',
    '/images/icons/icon-512x512.png',
    '/js/index.js',
    '/js/css-lint.js',
    '/js/difflib.js',
    '/js/diffview.js',
    '/js/ipsum-generator.js',
    '/js/json2.js',
    '/js/json-lint.js',
    '/js/jsonlint.js',
    '/js/lorem-ipsum.js',
    '/js/materialize.js',
    '/js/visual-difference.js',
    '/bower_components/codemirror/lib/codemirror.js',
    '/bower_components/codemirror/mode/javascript/javascript.js',
    '/bower_components/codemirror/mode/css/css.js',
    '/bower_components/codemirror/addon/edit/matchbrackets.js',
    '/bower_components/codemirror/addon/comment/continuecomment.js',
    '/bower_components/codemirror/addon/comment/comment.js',
    '/bower_components/ft-csslint/dist/csslint.js',
    '/bower_components/jquery/dist/jquery.slim.min.js',
    '/bower_components/kanye-ipsum/dist/jquery.kanye-ipsum.min.js',
    '/bower_components/codemirror/lib/codemirror.css',
    '/index.html',
    '/css-lint.html',
    '/ipsum-generator.html',
    '/json-lint.html',
    '/visual-difference.html',
    '/notfound.html',
    '/404.html'
];

self.addEventListener('install', (e) => {
    console.log('[ServiceWorker] Install');

    e.waitUntil(
        caches.open(cacheName).then((cache) => {
            console.log('[ServiceWorker] Caching app shell');
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('activate', (e) => {
    console.log('[ServiceWorker] Activate');

    e.waitUntil(
        caches.keys().then(function(keyList) {
            return Promise.all(keyList.map((key) => {
                if (key !== cacheName) {
                    console.log('[ServiceWorker] Removing old cache', key);
                    return caches.delete(key);
                }
            }));
        })
    );
});

self.addEventListener('fetch', (e) => {
    console.log('[ServiceWorker] Fetch', e.request.url);

    e.respondWith(
        caches.match(e.request).then((response) => {
            return response || fetch(e.request);
        })
    );
});

Тогда все файлы не были кэшированы из-за этого. Но если я удалю 404.html или переименую его в другое имя, работник службы будет работать нормально, и все файлы будут кэшироваться. Также странно, что на моем локальном сервере сервисный работник работает и кеширует 404.html, но в firebase происходит сбой.

Почему 404.html вызывает неперехваченную ошибку во время кэширования работника службы? Как мне решить это?

1 ответ

Вы не можете добавить страницу ошибки 404 html в кеш, если она возвращает 404 Статус https (как и положено).

Но вы все равно можете создать страницу с ошибкой 404 с помощью сервисного работника и использовать ее для сайта, не находящегося в кэше, даже если сайт находится в автономном режиме.

С помощью catch() после fetch() запросить и создать новый ответ

минималистичный пример:

// self is ServiceWorkerGlobalScope
self.addEventListener( 'fetch', function ( /** @type {FetchEvent} */ event )
{

    //const caches = ( event.target.caches );

    event.respondWith(
        caches.match( event.request ).then( ( /** @type {Response | undefined} */ response ) =>
        {

            if ( response ) {
                return response;
            }

            return fetch( event.request.clone() ).then( ( /** @type {Response} */ response ) =>
            {

                //…

                return response;
            }
            ).catch( () =>
            {
                return new Response( '<h1>404 - Not found</h1><p>more HTML here …</p>', {
                    status: 404,
                    statusText: 'Not found',
                    headers: new Headers( {
                        'Content-Type': 'text/html'
                    } )
                } );

            } );

        }
        )
    );

} );

Cache.addAll() это все или ничего API. Если какой-либо ответ не находится в диапазоне 200 кодов состояния HTTP, ничто не будет кэшировано.

cache.addAll будет отклонен, если какой-либо из ресурсов не сможет кэшироваться. Это означает, что сервисный работник будет устанавливать, только если все ресурсы в cache.addAll были кэшированы.

Firebase возвращается 404 Not Found для /404.html файл.

Подход к решению этой проблемы заключается в том, чтобы иметь файл /notfound.html как у вас, а затем вернуть это в fetch при необходимости.

Другие вопросы по тегам