Le formulaire est envoyé, l’indicateur apparaît et la console signale un jeton < inattendu dans JSON à la position 0. La page elle-même se charge bien, et c’est pourquoi le premier réflexe est d’accuser l’analyseur ou le tunnel. En général ni l’un ni l’autre n’est en cause : l’envoi est une requête différente du chargement de la page, et il est revenu avec quelque chose qui n’est pas du JSON. Travaillez dans l’ordre où le navigateur le révèle réellement, car les quatre réponses possibles demandent quatre corrections différentes.

Étape 1 : capturer l’envoi qui a vraiment eu lieu

Ouvrez le panneau Réseau avant d’envoyer, réglez le journal pour conserver les entrées d’une navigation à l’autre, puis faites un envoi de test inoffensif sur un compte que vous êtes autorisé à utiliser. Sélectionnez la requête déclenchée par le formulaire lui-même, et non la requête de document de la page.

Méfiez-vous des filtres. Un filtre XHR ou Fetch est pratique, mais si le framework envoie encore via une iframe cachée ou un formulaire créé dynamiquement, le filtre masquera la seule requête qui compte. Envoyez d’abord une fois sans filtre et regardez ce qui est apparu.

Pour la requête retenue, notez six choses avant toute interprétation : la méthode, l’URL complète avec la chaîne de requête, le statut, la chaîne de redirections, le Content-Type de la réponse et les premières lignes du corps. La référence du panneau Réseau de Chrome DevTools couvre les vues Headers, Response et Initiator où se trouvent ces éléments, et les panneaux équivalents des autres navigateurs affichent les mêmes champs.

Étape 2 : confirmer que c’est bien la requête attendue

Un nombre surprenant d’erreurs JSON sont en réalité des erreurs de routage. Si le gestionnaire d’envoi lève une exception avant d’appeler preventDefault, le navigateur effectue un POST natif du formulaire vers l’adresse indiquée par l’attribut action, et le serveur répond par une page HTML complète. Le gestionnaire ne s’exécute jamais, donc aucune requête JSON n’a été faite.

Comparez l’URL du panneau avec celle que votre JavaScript appelle. Cherchez une redirection qui aboutit ailleurs, une barre oblique finale manquante ou en trop, un décalage de méthode où le gestionnaire envoie GET alors que le point de terminaison accepte POST, ou un formulaire qui poste vers un chemin relatif depuis une page qui a déménagé. Suivez la chaîne de redirections jusqu’au bout et notez l’URL finale, pas la première.

Vérifiez ensuite l’initiateur. Si la requête vient d’une navigation de document et non de votre script, vous avez déjà trouvé le problème, et aucun changement d’analyseur de réponse n’aidera.

Étape 3 : classer le résultat en quatre catégories

Chaque résultat appartient à exactement une de ces catégories, et la catégorie décide où regarder ensuite.

What you seeCategoryWhere to look
Request never finishes, TLS or connection errorNo usable responseEndpoint reachability, certificate, front-end timeout
Request completes, script gets an opaque failureAccess blockedCross-origin policy, credentials mode, missing response header
200 with an HTML body or a login formWrong representationRedirect, expired session, route fallback, error handler
Body begins with a notice then valid JSONWrong representationServer-side warning output before serialisation
Valid JSON, framework rejects itContract mismatchEnvelope shape, field names, value types

Les lignes du milieu sont celles que l’on diagnostique mal, parce que le statut est 200. Une page de connexion atteinte après une redirection est une réponse HTTP parfaitement valable et un très mauvais document JSON. Le type de contenu application/json n’y remédie pas : c’est une étiquette, et un corps mal étiqueté échoue quand même à s’analyser. Accès bloqué est la ligne qui ressemble à une requête aboutie : le panneau affiche un statut, mais la politique d’origine croisée retient le corps, donc pour le script appelant elle est aussi inutilisable qu’un délai dépassé.

La quatrième ligne est tout aussi courante sur les piles PHP et les frameworks plus anciens. Un avertissement de dépréciation imprimé avant la charge encodée produit un corps qu’aucun analyseur JSON n’acceptera, et cet avertissement est souvent toute l’explication.

Étape 4 : lire l’erreur de l’analyseur au pied de la lettre

Le texte de l’erreur nomme le premier caractère qui a cassé l’analyse, ce qui identifie généralement la catégorie sans aucune conjecture.

Error text (Chrome/V8)What it means
Unexpected token < in JSON at position 0The body starts with markup: an HTML page or an error document
Unexpected end of JSON inputEmpty body, or the response was truncated
Unexpected token o in JSON at position 1You parsed something already parsed, typically an object rather than text
Unexpected token uThe body starts with the bare word undefined, usually an empty response rendered as a string

Un corps vide avec un 200 est un cas à part : le point de terminaison s’est exécuté, n’a rien produit, et quelque chose en aval l’a pris pour un succès. C’est une défaillance de contrat applicatif et non de transport, et sa place est à l’étape suivante, pas dans le proxy. Firefox et Safari formulent autrement les mêmes quatre défaillances, donc comparez sur le caractère ou sur le corps vide plutôt que sur la chaîne exacte.

Étape 5 : corriger la couche que les preuves désignent

Pour un problème de routage, corrigez la requête : rectifiez l’action, empêchez le gestionnaire de tomber dans le vide, alignez le point de terminaison et la méthode, puis retestez. Pour un problème de représentation, corrigez ce qui a produit le corps et cherchez pourquoi un document d’erreur revient là où des données étaient attendues. Pour un problème de contrat, lisez la structure réellement attendue par le framework pour la version que vous exécutez et conformez la réponse à celle-ci au lieu de relâcher le client.

Une réponse dont l’accès est bloqué demande sa propre passe, car la requête elle-même peut être correcte et le corps peut ne jamais atteindre votre code. Comparez l’Access-Control-Allow-Origin de la réponse avec l’Origin exact envoyé par le navigateur, et rappelez-vous qu’un joker ne satisfait pas une requête avec identifiants. Associez credentials: 'include' côté client à Access-Control-Allow-Credentials: true côté serveur, et vérifiez si l’appel a utilisé le mode no-cors, où un corps opaque est le résultat documenté et non un défaut.

Remplacer l’analyseur par quelque chose de permissif est la seule correction à éviter. Évaluer la réponse comme du code, ou retirer du texte jusqu’à ce qu’elle s’analyse, masque l’écart de contrat et ajoute une surface d’injection en échange du silence. De même, vérifier le statut séparément du corps est indispensable : un 200 portant un objet d’erreur applicatif est normal dans beaucoup d’API et doit être traité en lisant la charge.

Quand vous avez besoin d’aide, partagez un relevé minimal — méthode, URL, statut, URL finale après redirections, type de contenu de la réponse, forme du corps et contrat attendu — plutôt qu’un export brut. Les archives réseau contiennent des cookies, des jetons, des chaînes de requête et les données personnelles qui étaient dans le formulaire, et un assainisseur automatique n’est pas une relecture.

  • Capturez la requête sans filtre avant de changer le moindre code.
  • Confirmez que l’initiateur était votre script et que l’URL finale est votre point de terminaison.
  • Classez la réponse avant de toucher à l’analyseur.
  • Corrigez le routage, l’accès, la représentation ou le contrat, et jamais en relâchant l’analyseur.

Articles similaires