An HTTP status is part of the interface. A browser may render a friendly page, but a monitor, crawler, cache, and API client also need the status code and headers to tell the same story.
Permanent moves are not all interchangeable
308 Permanent Redirect communicates that the resource has a new permanent URI while preserving the request method. That is important for a client that sends POST, PUT, or another non-GET method. A redirect from an old page to a new page is easy to test with GET; a migration of an endpoint must also be tested with the method that real callers use.
curl -sS -D - -o /dev/null https://old.example.test/api/item
Without --location, curl leaves the redirect unfollowed. Resolve Location against the original URI: an absolute URI, root-relative path, or other relative reference can be valid. Check the resolved host, path, and scheme. 301/302 permit changing POST to GET; 307/308 preserve the method. Test state-changing methods only against an isolated endpoint. 308 is heuristically cacheable, subject to method and cache controls, so a cached move can outlive a server configuration change.
If the intent is to show a result after a completed action, 303 See Other points to a separate resource that the client can retrieve with GET or HEAD. It does not ask the client to replay the original write at a new address; choose that behavior deliberately rather than treating every redirect as a relocation.
Distinguish missing from removed
Use 404 Not Found when the server cannot find a current representation and the absence may be temporary or unknown. 410 Gone is stronger: it says access is no longer available and the condition is likely permanent; it does not establish why the resource disappeared. Both should have a body that helps a human, but neither should return 200 just because a custom error page rendered successfully.
404 can also conceal whether a forbidden resource exists. Both 404 and 410 are heuristically cacheable, subject to method and cache controls. Choose an explicit policy for error responses: a cached missing-route result can remain visible after the route is repaired.
The check belongs at the edge:
curl -sS -D missing.headers -o missing.html -w '%{http_code} %{url_effective}\n' \
https://www.example.test/a-route-that-does-not-exist
Keep the response headers on the error path. Security headers, a useful content type, and a correct status are more valuable than a decorative error animation.
Sources
- RFC 9110 — HTTP Semantics, sections 15 and 13, checked 2026-07-14.
- RFC 7538 — 308 Permanent Redirect, section 3, checked 2026-07-14.
- curl manual, status and redirect inspection flags, checked 2026-07-14.