Une requête a échoué. Il n’y a pas de code de statut, car aucune réponse n’a jamais arrivé. Et quand vous allez chercher dans votre journal d’accès la requête qui a échoué, il n’y a aucune ligne pour elle.

Cette combinaison est la signature d’une défaillance en dessous de HTTP, et ERR_HTTP2_PROTOCOL_ERROR est la façon la plus commune dont Chrome signale une telle chose. C’est utile d’y consacrer dix minutes parce que presque tout ce qui est écrit à ce sujet recommande le même contournement, et le contournement est un diagnostic que les gens confondent avec une guérison.

Ce que le code dit réellement

La liste des erreurs réseau de Chromium, d’où ces chaînes sont générées, la définit en six mots :

Il y a une erreur de protocole HTTP/2.

C’est toute l’entrée. Le nombre est -337, et rien en elle ne nomme une cause, une direction ou une partie. Rechercher cette chaîne vous donne mille pages qui devinent, car la source elle-même devine aussi.

Les six qui ne sont pas imprécises, et pourquoi c’est important

Voici la partie que personne ne mentionne. Chromium n’a pas une erreur HTTP/2. Il en a plusieurs, et chacune des autres est spécifique :

  • ERR_HTTP2_SERVER_REFUSED_STREAM, -351, que la source décrit longuement : le serveur « a refusé la requête sans la traiter » et l’a dit, soit avec une trame GOAWAY portant le code d’erreur NO_ERROR et un Last-Stream-ID en dessous de celui de cette requête, soit avec un RST_STREAM et REFUSED_STREAM. Le commentaire ajoute le détail opérationnel : « Le client PEUT réessayer (sur une connexion différente). »
  • ERR_HTTP2_PING_FAILED, -352 : « Le serveur HTTP/2 n’a pas répondu au message PING. »
  • ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY, -360 : « La sécurité du transport est inadéquate pour la version HTTP/2. »
  • ERR_HTTP2_FLOW_CONTROL_ERROR, -361, ERR_HTTP2_FRAME_SIZE_ERROR, -362, et ERR_HTTP2_COMPRESSION_ERROR, -363.

Donc quand vous obtenez -337 au lieu d’une de celles-ci, vous avez appris quelque chose de réel : ce n’était pas un flux refusé, pas un keepalive mort, pas un problème de chiffrement, pas du contrôle de flux, pas une taille de trame, pas une compression d’en-tête. ERR_HTTP2_PROTOCOL_ERROR est le « aucune des précédentes » de HTTP/2, et les précédentes sont six choses nommées que vous pouvez maintenant cesser d’enquêter.

C’est un résultat plus petit qu’une cause, et c’est bien mieux que rien, ce que le message en lui-même semble offrir.

Pourquoi vos journaux sont vides

La raison pour laquelle il n’y a pas de ligne de journal d’accès est dans la spécification, et c’est utile à lire car cela explique aussi pourquoi un utilisateur signale plusieurs choses qui se brisent à la fois.

RFC 9113 sépare deux sortes de défaillance. « Une erreur de flux est une erreur liée à un flux spécifique qui n’affecte pas le traitement des autres flux. » Une erreur de connexion est l’autre chose entièrement : « toute erreur qui empêche le traitement ultérieur de la couche trame ou corrompt un état de connexion. »

HTTP/2 multiplexe. Une connexion porte beaucoup de requêtes à la fois, donc une erreur de connexion ne fait pas échouer la requête qui l’a provoquée. Elle fait échouer chaque requête en vol sur cette connexion.

Ce que le rapport dit
Une page à moitié chargée, certaines images manquent et un envoi de formulaire n'a rien fait. Trois bugs séparés, fichés séparément
Ce qui s'est passé
Une erreur de connexion a fait tomber tout ce qui était en vol sur cette connexion au même instant. Une cause, trois symptômes, et pas de code de statut sur aucun d'eux

Et parce que l’échange n’a jamais été complété en tant que HTTP, il n’y a rien pour que votre serveur journalise. Pas de méthode, pas de chemin, pas de statut. L’utilisateur a regardé quelque chose échouer et vos journaux montrent un vide où cela aurait dû être.

Ce qui est sûr de réessayer, ce à quoi le protocole répond

C’est la question qui compte si un paiement ou un envoi de formulaire était en vol, et elle a une véritable réponse plutôt qu’un haussement d’épaules.

RFC 9113 dit qu’« une extrémité qui rencontre une erreur de connexion DEVRAIT d’abord envoyer une trame GOAWAY (Section 6.8) avec l’identifiant de flux du dernier flux qu’elle a reçu avec succès de sa contrepartie. »

Cet identifiant est une ligne tracée à travers les requêtes. Tout ce qui est numéroté au-dessus n’a pas été reçu, ce qui signifie qu’il n’a pas été traité, ce qui signifie que le réessayer ne peut pas dupliquer quoi que ce soit. C’est précisément pourquoi le propre commentaire de Chromium sur un flux refusé dit que le client peut réessayer sur une connexion différente.

Le problème, c’est que cette information existe environ une seconde, à l’intérieur du navigateur, puis elle est partie. Elle n’est pas dans votre journal du serveur, car les trames qui l’ont portée sont en dessous de la couche que votre serveur journalise.

Session Replay

Extension Chrome gratuite. Un clic sur la page qui se comporte mal capture la capture d'écran, la console et le journal réseau, et vous rend un lien à coller dans le ticket.

Installer l'extension

« Désactiver HTTP/2 » est un diagnostic, pas une correction

Le conseil que vous trouverez partout est de désactiver HTTP/2 et voir si le problème s’arrête. C’est un bon conseil et il est largement mal lu.

Si les erreurs s’arrêtent, vous avez appris où la faute vit : quelque chose dans la couche HTTP/2 entre cet utilisateur et vous traite mal les trames. Vous n’avez pas appris que HTTP/2 n’est pas fiable, et vous n’avez rien corrigé. Vous avez désactivé le multiplexage pour chaque visiteur afin de contourner le bug d’un tiers.

Ce tiers n’est généralement pas votre serveur. Les causes courantes sont les choses au milieu : un proxy inverse ou un équilibreur de charge avec sa propre implémentation HTTP/2, une arête CDN, un équipement réseau d’entreprise qui termine et rétablit TLS, et un logiciel de sécurité sur la machine de l’utilisateur faisant de même. Chacun d’eux parle HTTP/2 en votre nom, et chacun est un endroit où une trame peut être mal formée sans que personne des deux côtés ne fasse rien de mal.

C’est pourquoi cela affecte souvent un bureau, un FAI ou un produit antivirus, et personne d’autre.

Ce que demander à la personne qui l’a trouvée

Deux questions, et la seconde en vaut plus qu’il n’y paraît.

La chaîne exacte de la console ou de la page d’erreur. ERR_HTTP2_PROTOCOL_ERROR et ERR_HTTP2_SERVER_REFUSED_STREAM sont des problèmes différents avec des réponses différentes, et un rapport qui dit « une erreur réseau » a jeté la seule distinction qui était gratuite.

Cela se produit-il sur un réseau différent ? Si cela s’arrête sur les données mobiles, la cause est entre eux et vous plutôt que sur votre serveur, et vous l’avez réduit à l’équipement de leur réseau en une question. C’est le même test qui sépare un proxy d’entreprise d’un vrai problème de certificat sur l’écran la connexion n’est pas privée, et cela fonctionne ici pour la même raison.

Ce qu’il faut en retenir

Le message est imprécis parce que la source est imprécise, et savoir que cela vous arrête de lire du sens en lui qui n’y est pas. Ce qu’il vous dit, c’est tout ce qu’il n’est pas, et six alternatives nommées est un vrai rétrécissement.

Le reste découle de l’endroit où la défaillance se situe. Elle est en dessous de HTTP, donc il n’y a pas de code de statut et souvent pas de ligne de journal. C’est une erreur de connexion, donc elle prend plusieurs requêtes avec elle et arrive comme plusieurs rapports de bugs. Et la chose qui vous dirait si un réessai est sûr est une trame que le navigateur a vu et que votre serveur n’a jamais vue.

La liste de Chromium de ces erreurs, avec la définition d’une ligne pour chacune, est net_error_list.h, et le protocole lui-même est RFC 9113.