Una richiesta è fallita. Non c’è codice di stato, perché nessuna risposta è mai arrivata. E quando vai a cercare nel tuo access log la richiesta che è fallita, non c’è nemmeno una riga per essa.

Quella combinazione è la firma di un guasto sottostante all’HTTP, e ERR_HTTP2_PROTOCOL_ERROR è il modo più comune con cui Chrome ne segnala uno. Vale dieci minuti perché quasi tutto quello che è scritto su di esso consiglia lo stesso workaround, e il workaround è una diagnosi che le persone scambiano per una cura.

Quello che il codice dice effettivamente

L’elenco di Chromium degli errori di rete, dal quale queste stringhe sono generate, lo definisce in sei parole:

C’è un errore di protocollo HTTP/2.

Questa è l’intera voce. Il numero è -337, e nulla in esso nomina una causa, una direzione o una parte. Cercare la stringa ti restituisce mille pagine che indovinano, perché la fonte stessa sta indovinando anche lei.

I sei che non sono vaghi, e perché questo conta

Ecco la parte che nessuno menziona. Chromium non ha un solo errore HTTP/2. Ne ha diversi, e ogni altro è specifico:

  • ERR_HTTP2_SERVER_REFUSED_STREAM, -351, che la fonte descrive a lungo: il server “ha rifiutato la richiesta senza elaborarla” e lo ha detto, o con un frame GOAWAY che trasporta il codice di errore NO_ERROR e un Last-Stream-ID inferiore allo stream di questa richiesta, o un RST_STREAM con REFUSED_STREAM. Il commento aggiunge il dettaglio operativo: “Il client PUÒ riprovare (su una connessione diversa).”
  • ERR_HTTP2_PING_FAILED, -352: “Il server HTTP/2 non ha risposto al messaggio PING.”
  • ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY, -360: “La sicurezza del trasporto è inadeguata per la versione HTTP/2.”
  • ERR_HTTP2_FLOW_CONTROL_ERROR, -361, ERR_HTTP2_FRAME_SIZE_ERROR, -362, e ERR_HTTP2_COMPRESSION_ERROR, -363.

Quindi quando ricevi -337 invece di uno di quelli, hai imparato qualcosa di reale: non era uno stream rifiutato, non era un keepalive morto, non era un problema di cifratura, non era flow control, non era una dimensione di frame, non era compressione di header. ERR_HTTP2_PROTOCOL_ERROR è il “nessuno dei precedenti” dell’HTTP/2, e i precedenti sono sei cose nominate che puoi ora smettere di investigare.

Questo è un risultato più piccolo di una causa, ed è molto meglio di niente, che è quello che il messaggio da solo sembra offrire.

Perché i tuoi log sono vuoti

Il motivo per cui non c’è una riga di access log è nella specifica, e vale la pena leggerlo perché spiega anche perché un utente segnala vari guasti contemporaneamente.

RFC 9113 separa due tipi di fallimento. “Un errore di stream è un errore relativo a uno stream specifico che non influisce sull’elaborazione di altri stream.” Un errore di connessione è un’altra cosa completamente: “qualsiasi errore che impedisce ulteriore elaborazione del livello frame o corrompe qualsiasi stato di connessione.”

HTTP/2 esegue il multiplexing. Una connessione trasporta molte richieste contemporaneamente, quindi un errore di connessione non fa fallire la richiesta che l’ha provocato. Fa fallire ogni richiesta in volo su quella connessione.

Quello che dice la segnalazione
Una pagina mezza caricata, alcune immagini mancano e un invio di modulo non ha fatto nulla. Tre bug separati, segnalati separatamente
Quello che è successo
Un errore di connessione ha abbattuto tutto quello in volo su quella connessione nello stesso istante. Una causa, tre sintomi, e nessun codice di stato su nessuno di essi

E poiché lo scambio non è mai stato completato come HTTP, non c’è nulla per il tuo server da registrare. Nessun metodo, nessun percorso, nessuno stato. L’utente ha visto qualcosa fallire e i tuoi log mostrano un vuoto dove avrebbe dovuto essere.

Cosa si può riprovare in sicurezza, e qui il protocollo risponde

Questa è la domanda che conta se un pagamento o un invio di modulo era in volo, e ha una risposta reale piuttosto che un’alzata di spalle.

RFC 9113 dice che “un endpoint che incontra un errore di connessione DOVREBBE prima inviare un frame GOAWAY (Sezione 6.8) con l’identificatore dello stream dell’ultimo stream che ha ricevuto con successo dal suo peer.”

Quell’identificatore è una linea tracciata attraverso le richieste. Qualsiasi cosa numerata sopra di esso non è stata ricevuta, il che significa che non è stata elaborata, il che significa che riprovare non può duplicare nulla. Questo è precisamente il motivo per cui la nota di Chromium su uno stream rifiutato dice che il client può riprovare su una connessione diversa.

Il rovescio della medaglia è che questa informazione esiste per circa un secondo, dentro il browser, e poi è sparita. Non è nel tuo server log, perché i frame che l’hanno trasportata sono sotto il livello che il tuo server registra.

Session Replay

Estensione gratuita per Chrome. Un clic sulla pagina che si comporta male cattura lo screenshot, la console e il registro di rete, e ti restituisce un link da incollare nel ticket.

Installa l'estensione

“Disattiva HTTP/2” è una diagnosi, non una soluzione

Il consiglio che troverai ovunque è disabilitare HTTP/2 e vedere se il problema si ferma. È un buon consiglio ed è ampiamente frainteso.

Se gli errori si fermano, hai imparato dove vive il difetto: qualcosa nel livello HTTP/2 tra quell’utente e te sta gestendo male i frame. Non hai imparato che HTTP/2 è inaffidabile, e non hai corretto nulla. Hai disattivato il multiplexing per ogni visitatore al fine di aggirare il bug di una parte.

Quella parte di solito non è il tuo server. Le cause comuni sono le cose nel mezzo: un reverse proxy o load balancer con la propria implementazione HTTP/2, un edge CDN, apparecchiature di rete aziendale che terminano e ristabiliscono TLS, e software di sicurezza sulla macchina dell’utente stesso che fa la stessa cosa. Ognuno di questi parla HTTP/2 per tuo conto, e ognuno è un posto dove un frame può essere malformato senza che nessuno da entrambi i lati faccia nulla di sbagliato.

Per questo spesso colpisce un ufficio, un ISP o un prodotto antivirus, e nessun altro.

Cosa chiedere alla persona che ci è incappata

Due domande, e la seconda vale più di quanto sembra.

La stringa esatta dalla console o dalla pagina di errore. ERR_HTTP2_PROTOCOL_ERROR e ERR_HTTP2_SERVER_REFUSED_STREAM sono problemi diversi con risposte diverse, e una segnalazione che dice “un errore di rete” ha buttato via l’unica distinzione che era gratuita.

Accade su una rete diversa? Se si ferma sui dati mobili, la causa è tra loro e te piuttosto che sul tuo server, e l’hai ristretta alle apparecchiature della loro rete con una sola domanda. Questo è lo stesso test che separa un proxy aziendale da un vero problema di certificato nella schermata la connessione non è privata, e funziona qui per lo stesso motivo.

Cosa portare via da questo

Il messaggio è vago perché la fonte è vaga, e sapere questo ti impedisce di leggerci un significato che non c’è. Quello che invece ti dice è tutto quello che non è, e sei alternative nominate è un vero restringimento.

Il resto segue da dove il fallimento siede. È sotto HTTP, quindi non c’è codice di stato e spesso nessuna riga di log. È un errore di connessione, quindi porta con sé diverse richieste e arriva come diverse segnalazioni. E la cosa che ti direbbe se riprovare è sicuro è un frame che il browser ha visto e il tuo server non ha mai visto.

L’elenco di Chromium di questi errori, con la definizione di una riga di ciascuno, è net_error_list.h, e il protocollo stesso è RFC 9113.