HTTP Cookie への非同期アクセス

Victor Costan

Cookie Store API とは

Cookie Store API は HTTP Cookie を Service Worker に公開し、document.cookie に代わる非同期の API を提供します。この API を使用すると、次のことが簡単に行えます。

  • Cookie に非同期でアクセスして、メインスレッドでのジャンクを回避します。
  • Cookie の変更を検出できるため、Cookie のポーリングは避けてください。
  • Service Worker から Cookie にアクセスする。

説明を読む

現在のステータス

ステップ ステータス
1. 説明を作成する 完了
2. 仕様の最初の下書きを作成する 完了
**3. フィードバックを収集し、仕様を反復処理する** **処理中**
4. オリジン トライアル 一時停止
5. リリース 開始していません

非同期 Cookie ストアを使用するにはどうすればよいですか?

オリジン トライアルを有効にする

ローカルで試すには、コマンドラインで API を有効にします。

chrome --enable-blink-features=CookieStore

コマンドラインでこのフラグを渡すと、現在のセッションの Chrome で API がグローバルに有効になります。

または、chrome://flags#enable-experimental-web-platform-features フラグを有効にすることもできます。

Cookie は(おそらく)必要ない

新しい API について説明する前に、Cookie は引き続きウェブ プラットフォームで最も不適切なクライアントサイド ストレージ プリミティブであり、最後の手段として使用すべきであることを明記しておきます。これは偶然ではありません。Cookie はウェブ初のクライアントサイド ストレージ メカニズムであり、それ以降、多くのことを学んできました。

クッキーを避ける主な理由は次のとおりです。

  • Cookie を使用すると、ストレージ スキーマをバックエンド API に持ち込むことができます。各 HTTP リクエストは、Cookie ジャーのスナップショットを運びます。これにより、バックエンド エンジニアは現在の Cookie 形式に依存関係を簡単に導入できます。このような状態になると、フロントエンドは、バックエンドに一致する変更をデプロイせずにストレージ スキーマを変更できなくなります。

  • Cookie には複雑なセキュリティ モデルがあります。最新のウェブ プラットフォーム機能は同じオリジン ポリシーに従います。つまり、各アプリケーションは独自のサンドボックスを取得し、ユーザーが実行している他のアプリケーションとは完全に独立しています。Cookie スコープを使用すると、セキュリティの内容が大幅に複雑になります。要約しようとするだけで、この記事のサイズが 2 倍になります。

  • Cookie はパフォーマンス コストが高いため、ブラウザでは、すべての HTTP リクエストに Cookie のスナップショットを含める必要があるため、Cookie への変更はすべてストレージ スタックとネットワーク スタックに伝播する必要があります。最新のブラウザでは Cookie ストアの実装が高度に最適化されていますが、ネットワーク スタックと通信する必要がない他のストレージ メカニズムほど Cookie を効率化することはできません。

上記の理由から、最新のウェブ アプリケーションでは、Cookie の使用を避け、代わりにセッション ID を IndexedDB に保存し、fetch API を介して特定の HTTP リクエストのヘッダーまたは本文に ID を明示的に追加する必要があります。

とはいえ、Cookie を使用する正当な理由があるため、この記事を読み続けているのでしょう。

長い歴史を持つ document.cookie API は、アプリのジャンクが発生することがかなり保証されています。たとえば、document.cookie ゲッターを使用すると、リクエストした Cookie 情報が取得されるまで、ブラウザは JavaScript の実行を停止する必要があります。これにより、プロセスのホップやディスクの読み取りが発生し、UI のジャンクが発生します。

この問題を簡単に解決するには、document.cookie ゲッターから非同期 Cookie Store API に切り替えます。

await cookieStore.get('session_id');

// {
//   domain: "example.com",
//   expires: 1593745721000,
//   name: "session_id",
//   path: "/",
//   sameSite: "unrestricted",
//   secure: true,
//   value: "yxlgco2xtqb.ly25tv3tkb8"
// }

document.cookie セッターも同様の方法で置き換えることができます。変更が適用されるのは、cookieStore.set によって返された Promise が解決された後のみです。

await cookieStore.set({name: 'opt_out', value: '1'});

// undefined

ポーリングではなくモニタリング

JavaScript から Cookie にアクセスする一般的なアプリケーションは、ユーザーがログアウトしたときに検出して UI を更新するものです。現在、これは document.cookie のポーリングによって行われていますが、ジャンクが発生し、バッテリー駆動時間に悪影響を及ぼします。

Cookie Store API は、ポーリングを必要としない、Cookie の変更を検出する代替方法を提供します。

cookieStore.addEventListener('change', event => {
  for (const cookie of event.changed) {
    if (cookie.name === 'session_id') sessionCookieChanged(cookie.value);
  }
  for (const cookie of event.deleted) {
    if (cookie.name === 'session_id') sessionCookieChanged(null);
  }
});

サービス ワーカーを歓迎する

同期設計のため、document.cookie API はサービス ワーカーで使用できません。Cookie Store API は非同期であるため、Service Worker で使用できます。

Cookie の操作は、ドキュメントのコンテキストでも Service Worker でも同じように機能します。

// Works in documents and service workers.
async function logOut() {
  await cookieStore.delete('session_id');
}

ただし、Service Worker では Cookie の変更の検出方法が少し異なります。Service Worker を起動するとコストがかかる可能性があるため、Worker が関係する Cookie の変更を明示的に記述する必要があります。

次の例では、IndexedDB を使用してユーザーデータをキャッシュに保存するアプリケーションが、セッション Cookie の変更をモニタリングし、ユーザーがログオフするとキャッシュに保存されたデータを破棄します。

// Specify the cookie changes we're interested in during the install event.
self.addEventListener('install', event => {
  event.waitUntil(cookieStore.subscribeToChanges([{name: 'session_id'}]));
});

// Delete cached data when the user logs out.
self.addEventListener('cookiechange', event => {
  for (const cookie of event.deleted) {
    if (cookie.name === 'session_id') {
      indexedDB.deleteDatabase('user_cache');
      break;
    }
  }
});

ベスト プラクティス

近日提供予定。

フィードバック

この API をお試しいただいた場合は、ぜひご感想をお聞かせください。API シェイプに関するフィードバックは仕様リポジトリに転送し、実装のバグは Blink>Storage>CookiesAPI Blink コンポーネントに報告してください。

特に、説明に記載されているもの以外のパフォーマンス測定とユースケースについて、ご意見をお聞かせください。

参考情報