05 - Les codes de statut
Ce que tu vas apprendre
- Les 5 familles de codes de statut et leur logique
- Les codes que tu croiseras vraiment en production
- Les abus courants et pourquoi ils posent problème
- Quel code utiliser dans quel contexte
Prerequisites
Avoir lu 03 - La réponse HTTP pour comprendre la status line.
Il y a un test que je fais parfois en entretien technique. Je demande : "quelle est la différence entre 401 et 403 ?" La réponse correcte est simple, mais je suis toujours surpris du nombre de devs seniors qui hesitent. Et je ne les blame pas -- moi-meme j'ai confondu les deux pendant des annees.
Les codes de statut sont un vocabulaire. Comme tout vocabulaire, il faut l'apprendre une fois pour le maîtriser. Cet article est la référencé que j'aurais voulu avoir a portee de main.
La logique des familles
Le premier chiffre donne la categorie :
1xx - Information (la requete est en cours de traitement)
2xx - Succes (la requete a reussi)
3xx - Redirection (va voir ailleurs)
4xx - Erreur client (tu as fait une erreur)
5xx - Erreur serveur (j'ai fait une erreur)
Regle d'or : si tu ne connais pas un code spécifique, le comportement par défaut de la famille s'applique. Un 299 inconnu se comporte comme un 200.
1xx - Informationnel
Les 1xx sont des réponses intermediaires. Le serveur dit "j'ai compris, continue."
100 Continue : le client a envoye les headers avec Expect: 100-continue. Le serveur répond 100 pour dire "ok, envoie le body." Utile pour les gros uploads : pourquoi envoyer 500 MB de body si le serveur va rejeter la requête a cause d'un header manquant ?
# Le client demande la permission
POST /api/upload HTTP/1.1
Host: api.example.com
Content-Length: 524288000
Expect: 100-continue
# Le serveur donne le feu vert
HTTP/1.1 100 Continue
# Le client envoie le body
[524 MB de donnees]
# Le serveur repond pour de vrai
HTTP/1.1 201 Created
101 Switching Protocols : le serveur accepte de changer de protocole. C'est le mecanisme utilise pour l'upgrade vers WebSocket :
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Apres ce 101, la connexion n'est plus du HTTP. C'est du WebSocket.
2xx - Succes
200 OK : la requête a reussi. Le body contient le résultat. C'est le code par défaut pour les GET reussis.
201 Created : une nouvelle ressource a ete créée. Le header Location devrait pointer vers la nouvelle ressource :
HTTP/1.1 201 Created
Location: /api/users/42
Content-Type: application/json
{"id": 42, "name": "Alice"}
204 No Content : la requête a reussi mais il n'y a rien a retourner. Typique pour les DELETE et les PUT reussis quand le client n'a pas besoin de la ressource mise à jour.
HTTP/1.1 204 No Content
Pas de body. Pas de Content-Length. Rien.
206 Partial Content : le serveur retourne une partie de la ressource. Utilise pour le telechargement partiel (résumé download) et le streaming video :
GET /video.mp4 HTTP/1.1
Range: bytes=1000-1999
HTTP/1.1 206 Partial Content
Content-Range: bytes 1000-1999/50000
Content-Length: 1000
3xx - Redirection
Les 3xx redirigent le client vers une autre URL. Le header Location contient la destination.
301 Moved Permanently : la ressource a change d'URL définitivement. Les navigateurs et les moteurs de recherche mettent à jour leurs références. Le cache stocke cette redirection.
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-page
Attention : historiquement, les navigateurs changeaient la méthode POST en GET lors d'un 301. C'est un bug devenu standard.
302 Found : redirection temporaire. Meme problème que 301 avec le changement de méthode.
304 Not Modified : pas vraiment une redirection. Le client a envoye un header conditionnel (If-None-Match ou If-Modified-Since), et le serveur dit "rien n'a change, utilise ta copie en cache." Pas de body dans la réponse.
GET /api/data HTTP/1.1
If-None-Match: "abc123"
HTTP/1.1 304 Not Modified
ETag: "abc123"
307 Temporary Redirect : comme 302 mais garantit que la méthode ne change pas. Un POST redirige vers un POST.
308 Permanent Redirect : comme 301 mais garantit que la méthode ne change pas.
Mon conseil : utilise 307 au lieu de 302, et 308 au lieu de 301, si tu veux etre sur que la méthode est preservee. En pratique, les navigateurs modernes gerent correctement 301/302, mais les clients HTTP programmatiques (curl, fetch) peuvent varier.
4xx - Erreur client
C'est la famille la plus riche et celle ou les abus sont les plus frequents.
400 Bad Request : la requête est mal formee. JSON invalide, paramètre manquant, format incorrect. C'est le "tu as foire" générique.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error": "Le champ 'email' est requis"}
401 Unauthorized : le client n'est pas authentifié. Pas "pas autorise" -- pas authentifié. Le nom du code est trompeur. Le serveur devrait inclure un header WWW-Authenticate pour dire au client comment s'authentifier.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
403 Forbidden : le client est authentifié mais n'a pas la permission. Le serveur sait qui tu es, mais tu n'as pas le droit. Contrairement a 401, s'authentifier a nouveau ne changera rien.
La distinction 401/403 : 401 = "qui es-tu ?" et 403 = "je sais qui tu es, et la réponse est non."
404 Not Found : la ressource n'existe pas. Aussi utilise quand le serveur veut cacher l'existence d'une ressource (un 403 revelerait qu'elle existe).
405 Method Not Allowed : la méthode n'est pas supportee pour cette ressource. Le serveur doit inclure un header Allow :
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST
409 Conflict : la requête entre en conflit avec l'état actuel du serveur. Typique pour les mises à jour concurrentes ou les doublons.
413 Content Too Large : le body est trop gros. Nginx retourne ca quand tu depasses client_max_body_size.
415 Unsupported Media Type : le Content-Type n'est pas supporte. Tu envoies du XML mais le serveur n'accepte que du JSON.
422 Unprocessable Content : la requête est syntaxiquement correcte mais semantiquement invalide. Le JSON est valide, mais les donnees ne passent pas la validation métier.
La frontiere entre 400 et 422 est floue. Ma regle : 400 pour les erreurs de format (JSON casse, paramètre manquant), 422 pour les erreurs de validation métier (email deja pris, montant negatif).
429 Too Many Requests : rate limiting. Le client envoie trop de requêtes. Le header Retry-After indique quand reessayer :
HTTP/1.1 429 Too Many Requests
Retry-After: 60
451 Unavailable For Legal Reasons : la ressource est bloquee pour des raisons legales. Le numero est une référencé a Fahrenheit 451 de Ray Bradbury. C'est le genre de détail qui me fait aimer les gens qui ecrivent les specs HTTP.
5xx - Erreur serveur
500 Internal Server Error : le serveur a plante. Exception non geree, bug, crash. Si tu retournes 500 pour une erreur de validation, tu confonds l'erreur du client avec l'erreur du serveur.
502 Bad Gateway : le serveur agit comme proxy et a reçu une réponse invalide du serveur en amont. Typique : nginx recoie du garbage du serveur Node.js qui a crashe.
503 Service Unavailable : le serveur est temporairement indisponible. Maintenance, surcharge, déploiement. Le header Retry-After peut indiquer quand revenir.
504 Gateway Timeout : le proxy n'a pas reçu de réponse du serveur en amont dans le delai imparti. Tu vois ca quand ton backend met trop de temps a répondre et que nginx ou le load balancer coupe.
Les abus courants
200 pour tout : le serveur retourne toujours 200 avec un champ error dans le body. Les caches stockent les erreurs comme des succes. Les outils de monitoring ne detectent rien. GraphQL fait ca par design, et c'est un de mes reproches envers le protocole.
# Anti-pattern
HTTP/1.1 200 OK
{"error": true, "message": "User not found"}
# Correct
HTTP/1.1 404 Not Found
{"message": "User not found"}
500 pour les erreurs de validation : si le client envoie des donnees invalides, c'est une erreur client (4xx), pas une erreur serveur (5xx). Un 500 pour "email invalide" fausse tes metriques d'erreur et déclenché des alertes inutiles.
403 au lieu de 404 : retourner 403 pour une ressource qui n'existe pas revele qu'elle n'existe pas. Parfois c'est pas grave, parfois ca permet a un attaquant d'enumerer les ressources.
Sur paltemps.fr, on a une convention : les erreurs métier retournent 4xx avec un body JSON structure qui contient un code d'erreur interne et un message lisible. Les 5xx sont reserves aux vrais plantages.
Résumé
- 1xx = info, 2xx = succes, 3xx = redirection, 4xx = erreur client, 5xx = erreur serveur
- 401 = pas authentifié, 403 = pas autorise (le nom 401 est trompeur)
- 307/308 preservent la méthode, 301/302 peuvent la changer
- 400 pour les erreurs de format, 422 pour les erreurs de validation métier
- Ne retourne jamais 200 pour une erreur -- ca casse les caches et le monitoring
- 429 avec Retry-After pour le rate limiting
Precedent : 04 - Les méthodes HTTP Suivant : 06 - Les headers HTTP