Accesso asincrono ai cookie HTTP

Victor Costan

Che cos'è l'API Cookie Store?

L'API Cookie Store espone i cookie HTTP ai worker di servizio e offre un'alternativa asincrona a document.cookie. L'API semplifica:

  • Evita i problemi nel thread principale accedendo ai cookie in modo asincrono.
  • Evita di eseguire il polling per i cookie, perché le modifiche ai cookie possono essere osservate.
  • Accedere ai cookie dai service worker.

Leggi la spiegazione

Stato attuale

Passaggio Stato
1. Creare un video esplicativo Completato
2. Creare una bozza iniziale della specifica Completato
**3. Raccogli feedback e esegui l'iterazione sulle specifiche** **In corso**
4. Prova dell'origine In pausa
5. Lancio Non avviato

Come faccio a utilizzare l'archivio cookie asincrono?

Attiva la prova dell'origine

Per provarla localmente, l'API può essere abilitata sulla riga di comando:

chrome --enable-blink-features=CookieStore

Se passi questo flag sulla riga di comando, l'API viene attivata a livello globale in Chrome per la sessione corrente.

In alternativa, puoi attivare il #enable-experimental-web-platform-features flag in chrome://flags.

(Probabilmente) non hai bisogno di cookie

Prima di esaminare la nuova API, vorrei affermare che i cookie sono ancora la peggiore primitiva di archiviazione lato client della piattaforma web e devono essere utilizzati come ultima risorsa. Non è un caso: i cookie sono stati il primo meccanismo di archiviazione lato client del web e da allora abbiamo imparato molto.

I motivi principali per cui è consigliabile evitare i cookie sono:

  • I cookie importano lo schema di archiviazione nell'API di backend. Ogni richiesta HTTP contiene un'istantanea del cookie jar. In questo modo, gli sviluppatori back-end possono facilmente introdurre dipendenze sul formato corrente dei cookie. In questo caso, il front-end non può modificare lo schema di archiviazione senza implementare una modifica corrispondente nel back-end.

  • I cookie hanno un modello di sicurezza complesso. Le funzionalità della piattaforma web moderna seguono lo stesso criterio di origine, il che significa che ogni applicazione ha la propria sandbox ed è completamente indipendente dalle altre applicazioni in esecuzione dall'utente. Gli ambiti dei cookie rappresentano un argomento di sicurezza molto più complesso e il semplice tentativo di riassumerlo raddoppierebbe le dimensioni di questo articolo.

  • I cookie hanno costi elevati per le prestazioni. I browser devono includere uno snapshot dei tuoi cookie in ogni richiesta HTTP, pertanto ogni modifica ai cookie deve essere propagata negli stack di rete e di archiviazione. I browser moderni hanno implementazioni del cookie store altamente ottimizzate, ma non saremo mai in grado di rendere i cookie efficienti come gli altri meccanismi di archiviazione, che non devono comunicare con lo stack di rete.

Per tutti i motivi sopra indicati, le applicazioni web moderne dovrebbero evitare i cookie e memorizzare un identificatore di sessione in IndexedDB e aggiungere esplicitamente l'identificatore all'intestazione o al corpo di richieste HTTP specifiche tramite l'API fetch.

Detto questo, se stai ancora leggendo questo articolo è perché hai un buon motivo per utilizzare i cookie…

L'API vettusta document.cookie è una fonte abbastanza garantita di problemi per la tua applicazione. Ad esempio, ogni volta che utilizzi il getter document.cookie, il browser deve interrompere l'esecuzione di JavaScript finché non dispone delle informazioni sui cookie che hai richiesto. Questo può richiedere un salto di processo o una lettura del disco e causare un tremolio dell'interfaccia utente.

Una soluzione semplice a questo problema è passare dal getter document.cookie all'API Cookie Store asincrona.

await cookieStore.get('session_id');

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

Il set document.cookie può essere sostituito in modo simile. Tieni presente che la modifica è garantita solo dopo la risoluzione della promessa restituita da cookieStore.set.

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

// undefined

Osserva, non fare sondaggi

Un'applicazione molto utilizzata per accedere ai cookie da JavaScript è il rilevamento della disconnessione dell'utente e l'aggiornamento dell'interfaccia utente. Attualmente questo viene fatto tramite il polling document.cookie, che introduce problemi di aggiornamento e ha un impatto negativo sulla durata della batteria.

L'API Cookie Store offre un metodo alternativo per osservare le modifiche ai cookie, che non richiede l'esecuzione di polling.

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);
  }
});

Benvenuti service worker

A causa del design sincrono, l'API document.cookie non è stata messa a disposizione dei service worker. L'API Cookie Store è asincrona e pertanto è consentita nei worker di servizio.

L'interazione con i cookie funziona allo stesso modo nei contesti dei documenti e nei worker di servizio.

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

Tuttavia, l'osservazione delle modifiche ai cookie è leggermente diversa nei worker di servizio. Riattivare un worker può essere piuttosto costoso, quindi dobbiamo descrivere esplicitamente le modifiche ai cookie che interessano il worker.

Nell'esempio seguente, un'applicazione che utilizza IndexedDB per memorizzare nella cache i dati utente monitora le modifiche al cookie della sessione e elimina i dati memorizzati nella cache quando l'utente esce.

// 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;
    }
  }
});

Best practice

Disponibile a breve.

Feedback

Se provi questa API, facci sapere cosa ne pensi. Invia i feedback sulla forma dell'API al repository delle specifiche e segnala i bug di implementazione al componente Blink Blink>Storage>CookiesAPI.

Ci interessano in modo particolare le misurazioni del rendimento e i casi d'uso diversi da quelli descritti nella spiegazione.

Risorse aggiuntive