3xx redirection
The resource is somewhere else
2xx codes mean everything is fine. 3xx codes mean something a bit different: “The thing you are looking for is not here. Let me tell you where it is.” The server uses the Location header to point the client to the right URL.
You see redirects all the time on the web without realizing it. When you type http://example.com and end up at https://example.com, that was a redirect. When a site changes its URL structure, old links still work because of redirects. They are a core part of how the web stays glued together.
301 Moved permanently
The resource has moved to a new URL, and it is never coming back. Bookmarks, search engines, and links should all update to the new URL.
HTTP/1.1 301 Moved Permanently
Location: https://api.example.com/v2/books When the browser sees a 301, it follows the Location header automatically. The user does not even notice. Use 301 when you permanently rename a URL, like migrating from /api/v1/books to /api/v2/books.
302 Found (temporary redirect)
The resource is temporarily at a different URL. The client should follow the redirect for this request, but keep using the original URL for future requests.
HTTP/1.1 302 Found
Location: https://api.example.com/maintenance Use 302 for temporary situations: the site is under maintenance, the user needs to log in first, or a short URL needs to resolve to the full URL. The key difference from 301 is that the original URL is still valid. The client should not update its bookmarks.
304 Not modified
This one is different from the other 3xx codes because it is not really a redirect. 304 means “the resource has not changed since the last time you fetched it, so use your cached copy.”
GET /books HTTP/1.1
If-None-Match: "abc123"
HTTP/1.1 304 Not Modified
ETag: "abc123" The client sends a header saying “I have version abc123 cached.” The server checks and says “that is still the latest version.” No body is sent, saving bandwidth. The client uses the copy it already has. This is covered in more depth in the Caching course’s ETag lesson.
307 and 308: method-preserving redirects
There is a subtle problem with 301 and 302. When a browser follows a 301 or 302 redirect, it sometimes changes the HTTP method to GET, even if the original request was a POST. This is a historical quirk from early browsers.
307 Temporary Redirect works like 302, but the client must use the same method. If you POST to a URL and get a 307, the redirect must also be a POST.
308 Permanent Redirect works like 301, but the client must use the same method. Same idea, but permanent.
In practice, 307 and 308 exist to fix the method-changing behavior of 302 and 301. If you are redirecting a POST or PUT request and need the method preserved, use 307 or 308.
When to use each
| Code | Meaning | Method changes? | Permanent? |
|---|---|---|---|
| 301 | Moved permanently | May change to GET | Yes |
| 302 | Found (temporary) | May change to GET | No |
| 304 | Not modified | N/A (no redirect) | N/A |
| 307 | Temporary redirect | Must keep same | No |
| 308 | Permanent redirect | Must keep same | Yes |
Redirects keep the web working when things move around. But what happens when the client sends a bad request? That is the next lesson: 4xx client errors.
Exercises
Exercise 1: Build a route that returns 301 with a Location header. Follow it with curl -L (the -L flag tells curl to follow redirects).
Exercise 2: Build a route that returns 304 when the If-None-Match header matches. Verify no body is sent.
Exercise 3: POST to a route that returns 307. Verify the redirect preserves the POST method.
What is the difference between 301 and 308?