バグのある Service Worker がデプロイされて、問題が発生する場合があります。たとえば、Service Worker は登録時に解析され、インストールが正常に完了することがあります。しかし、fetch
イベントのコードにバグがあると、リクエストに応答せず、空白のページが発生する可能性があります。また、ページのマークアップが積極的にキャッシュに保存され、Service Worker が後続のアクセスに対して Cache
インスタンスから古いマークアップ レスポンスのみを返す可能性もあります。
Service Worker はさまざまな形でバックファイアを実行しますが、これは本番環境のウェブサイトでは恐ろしい問題です。それでも、すべてが失われません。状況を解決して軌道に戻す方法はいくつかあります。
NoOps の Service Worker をデプロイする
バグのある Service Worker に対処するために必要なのは、基本的な no-op Service Worker をデプロイすることだけです。この Service Worker は、fetch
イベント ハンドラなしでインストールされ、すぐに有効になります。
// sw.js
self.addEventListener('install', () => {
// Skip over the "waiting" lifecycle state, to ensure that our
// new service worker is activated immediately, even if there's
// another tab open controlled by our older service worker code.
self.skipWaiting();
});
self.addEventListener('activate', () => {
// Optional: Get a list of all the current open windows/tabs under
// our service worker's control, and force them to reload.
// This can "unbreak" any open windows/tabs as soon as the new
// service worker activates, rather than users having to manually reload.
self.clients.matchAll({
type: 'window'
}).then(windowClients => {
windowClients.forEach((windowClient) => {
windowClient.navigate(windowClient.url);
});
});
});
install
イベントで self.skipWaiting()
を呼び出すと、この Service Worker はすぐにインストールされ、有効になります。必要に応じて、activate
イベントに追加のコードをデプロイして、Service Worker が制御している WindowClient
で他の開いているタブを強制的に再読み込みできます。
NoOps の Service Worker に fetch
イベント ハンドラが含まれないことが非常に重要です。Service Worker がリクエストを処理しない場合、これらのリクエストは Service Worker が存在しないかのようにブラウザに渡されます。NoOps の Service Worker をデプロイすると、バグのある Service Worker を修正して、後でアップデートとしてデプロイできます。
このアプローチがうまく機能するのは、ブラウザが Service Worker を HTTP キャッシュに格納することに対する強力な安全保護対策を備えていることと、Service Worker のコンテンツの更新をバイト単位でチェックするためです。これらのデフォルトにより、バグのある Service Worker の代わりに NoOps の代替機能をデプロイして、問題を迅速に解決できるようになります。
その他の取るべき対策
バグのある Service Worker は NoOps の Service Worker をデプロイするだけで解決できますが、必要に応じて追加の対策を講じることができます。
古い Service Worker の URL が不明な場合はどうすればよいでしょうか。
以前にインストールされた Service Worker の URL が不明な場合があります。これは、ファイルがバージョン管理されているため(ファイル名にハッシュが含まれているなど)可能性があります。この場合、登録される可能性のある各古い Service Worker の URL に一致する NoOps Service Worker のデプロイが困難な場合があります。これはベスト プラクティスに反します。デベロッパーは、デプロイされたすべての Service Worker バージョンのすべてのハッシュを記憶しているとは限らないためです。
幸いなことに、有用な HTTP リクエスト ヘッダーは、Service Worker スクリプトのリクエスト(Service-Worker
)とともに送信されます。ウェブサーバーで、このヘッダーを確認し、代わりに NoOps の Service Worker を提供するようにリクエストをインターセプトします。この作業は、使用するウェブサーバーとバックエンド スタックによって異なります。方法については、該当する言語のドキュメントをご覧ください。
今後の Service Worker のデプロイでは、バージョニングされていないアセット名(sw.js
など)を使用してください。これにより、その後の複雑さが軽減されます。
Clear-Site-Data
ヘッダーを設定する
一部のブラウザでは、値が 'storage'
の Clear-Site-Data
レスポンス ヘッダーが設定されている場合、オリジンのすべての Service Worker の登録が解除されます。ただし、このアプローチではいくつかの注意点があります。
- この操作を行うと、関連付けられた送信元のストレージがすべて消去されます。これには、
localStorage
、IndexedDB、sessionStorage
などのストレージが含まれます(送信元の HTTP キャッシュは含まれません)。 - このヘッダーは一部のブラウザではサポートされていません。
このヘッダーのサポートは合計ではないため、単独では問題を解決できません。そのため、NoOps の Service Worker をデプロイすることに加えて、Clear-Site-Data
を対策と見なすことをおすすめします。
損傷が解消しない
バグのある Service Worker によってユーザー エクスペリエンスが損なわれることは、特に大規模で有名なウェブサイトの場合、恐ろしいことですが、その被害は一時的なものであり、元に戻すことができます。
状況を修正するために NoOps の Service Worker をデプロイする必要がある場合は、後で時間をかけて問題を正確に把握してください。今後は、想定されたリクエストのみを Service Worker で処理するようにしてください。 ステージング環境で頻繁にテストを行い、確信が持てる場合にのみ更新をデプロイする。