7 min
  • HTTP

Status codes and redirects

Every HTTP response opens with three digits, and the first of them is the one that matters. A client that understands only the first digit still behaves correctly, which is exactly why the ranges are grouped the way they are.

RangeMeansWhat a client should do
1xxStill goingKeep waiting
2xxIt workedUse the response
3xxIt is somewhere elseGo there instead
4xxYour request was the problemFix the request; retrying won’t help
5xxOur end was the problemRetry may well help

The 4xx/5xx split is a statement about blame, and it is the most useful distinction in the whole list: it tells a client whether retrying is sensible. That is why a request that parsed cleanly and then said something impossible gets 422 rather than 400, and why a method that is simply wrong for an existing resource gets 405 — with an Allow field naming what would have worked.

Check yourself
A client sends valid JSON that references a user id that does not exist. Which status?

Redirects: four codes that disagree about POST

A 3xx says the thing you want is elsewhere and Location says where. The cost is a whole extra round trip before anything useful is served, and a chain of them costs one per hop.

Loading the HTTP Explorer simulation…

The codes differ on two axes — whether the move is permanent, and what happens to a POST:

CodePermanent?A POST becomes
301YesA GET (historically)
302NoA GET (historically)
303NoA GET, deliberately
307NoA POST, preserved
308YesA POST, preserved

The "historically" is not a footnote. Early browsers rewrote POST to GET on 301 and 302 in defiance of the specification, enough of the web came to depend on it that the behaviour was standardised, and 307 and 308 exist purely to provide the codes that mean what 302 and 301 were supposed to mean.

Predict what happens next
A form POST succeeds and the server answers 303 See Other. Why not just return the page?

Key takeaways

  • The first digit carries the meaning; a client that reads only that still behaves correctly.
  • The 4xx/5xx split tells a client whether retrying can possibly help, which makes it the most operationally useful distinction in HTTP.
  • Returning 200 with an error in the body lies to every cache, proxy and retry policy on the path.
  • Each redirect is a full extra round trip, and chains multiply it.
  • 301 and 302 turn a POST into a GET because browsers did it first; 307 and 308 exist to mean what those two were meant to mean.

Take it further