HTTP 302 means the resource you asked for is temporarily somewhere else, and the Location header tells you where. It is not an error. The catch is a forty-year-old quirk: browsers change a POST into a GET when they follow a 302, which is almost never what the API that issued it intended.
That quirk is why 302 has two modern replacements, and why reaching for 302 by reflex is usually the wrong call. The status code you want depends on two questions — is this move permanent, and does the request method need to survive?
Table of contents
- What a 302 response actually looks like
- The POST-to-GET problem
- 302 against 301: temporary against permanent
- When 302 is genuinely the right answer
- Debugging a 302 you did not expect
- Choosing without thinking about it
- How this fits the rest of the stack
- FAQ
What a 302 response actually looks like
A 302 is a status line and a Location header. That is the entire mechanism.
HTTP/1.1 302 Found
Location: https://example.com/temporary-page
Content-Length: 0
The client sees the 302, reads Location, and issues a fresh request to that URL. The body is usually empty because nobody reads it — though sending a short HTML body with a link is polite for clients that do not follow redirects automatically.
The name in the spec is Found, which is a leftover from an earlier draft where it was called Moved Temporarily. RFC 9110 still calls it Found. Nobody says that out loud; everybody says 302.
The POST-to-GET problem
Here is the behaviour that causes real bugs. The spec for 302 says the client should not change the request method. Browsers have ignored that since the mid-nineties, and RFC 9110 now documents the deviation as accepted reality.
So this happens:
- Your client POSTs a JSON body to /api/orders.
- Your server responds 302 with Location: /api/v2/orders.
- The browser issues a GET to /api/v2/orders — with no body.
- Your API returns a list of orders instead of creating one, and reports success.
Nothing errors. The order is simply never created. This is the single most expensive thing about 302, and it is why 307 exists: 307 Temporary Redirect is a 302 that guarantees the method and body are preserved.
If your redirect only ever sees GET traffic — which is true for most page-level redirects — the distinction does not matter. If an API endpoint might receive a POST, PUT, or DELETE, use 307 and stop thinking about it.
302 against 301: temporary against permanent
The other axis is permanence, and this is the one search engines care about.
- 301 Moved Permanently — the old URL is dead. Search engines transfer ranking signals to the new URL and eventually drop the old one from the index. Browsers cache the redirect aggressively, sometimes indefinitely.
- 302 Found — the old URL is still the real one. Search engines keep indexing the old URL and treat the new one as a temporary detour. Browsers do not cache it by default.
- 307 Temporary Redirect — a 302 that preserves the request method.
- 308 Permanent Redirect — a 301 that preserves the request method.
The costly mistake is using 302 for a permanent move. You migrate to a new domain, ship 302s, and months later the old URLs are still the ones ranking while the new ones sit unindexed. The redirect works perfectly for humans and does nothing for search.
The mirror-image mistake is using 301 for something temporary. Browsers cache 301s hard — often for the life of the profile — so a 301 you shipped for a two-hour maintenance window can outlive the maintenance by weeks on the machines that saw it. There is no way to remotely un-cache it.
When 302 is genuinely the right answer
It has real uses, and they share a shape: the destination depends on state that changes.
- Post-login redirects. Send an authenticated user from /login to wherever they were going. The target differs per user and per session.
- A/B tests and geo-routing. The destination depends on a cohort or a region, so it must not be cached.
- Short-lived maintenance pages. The real page is coming back; you do not want browsers remembering the detour.
- Signed download URLs. Redirect to a time-limited storage URL that will be invalid in an hour.
In each case the common thread is that caching the redirect would be wrong. That is what 302 buys you, and it is a real thing to buy.
Debugging a 302 you did not expect
Unexpected redirects are usually a chain, not a single hop. Follow the whole chain rather than looking at the first response:
curl -sIL https://example.com/page | grep -Ei '^(HTTP|location)'
The -L follows redirects and -I keeps it to headers. What you are looking for is the number of hops and where each one comes from. Three common culprits, in the order worth checking:
- HTTP to HTTPS upgrade at the edge or load balancer, which is often a 301 and fine.
- Trailing-slash normalisation in the framework or static host, which adds a hop on every request to a directory route.
- Auth middleware bouncing unauthenticated requests to a login page, which is the one that surprises API clients.
A redirect chain longer than two hops is worth flattening. Every hop is a full round trip, and search crawlers give up somewhere around five.
The other thing worth checking: redirect loops. If curl reports it exceeded the maximum redirects, you usually have two systems each convinced the other should be handling the canonical form — an edge rule adding a trailing slash and an application rule stripping it, for example.
Choosing without thinking about it
A short decision procedure that gets it right nearly every time:
- Is the old URL never coming back? Use 301. Otherwise use 302.
- Could this endpoint receive a POST, PUT, PATCH, or DELETE? Upgrade your answer to 308 or 307 respectively.
- Are you redirecting inside an API rather than a browser flow? Prefer 307 and 308 always — the method-preserving pair have no downside and remove an entire class of bug.
If you take one thing away: 307 and 308 are strictly better-defined versions of 302 and 301, and there is no compatibility reason to avoid them. Every browser and HTTP client in use has supported them for over a decade.
How this fits the rest of the stack
Redirects are configuration, which means they are the part of a site most likely to be right in one environment and wrong in another. Getting the status code correct is half of it; being able to see which rule fired is the other half. Static hosting on RunxBuild handles redirects and rewrites as declared rules rather than application code, so the redirect chain is something you read rather than reverse-engineer from logs. If you are working out what a site costs to run across static pages, an API, and a database, the RunxBuild hosting calculator breaks it into line items you can total up.
Useful related references:
- n8n HTTP Request Node: The Auth and Error Playbook
- HTTP Error 509: Bandwidth Limit Exceeded (and How to Fix It)
- HTTP 404 File Not Found: The Server Config, the Rewrites, the SPA Fallback, and the One Mistake That Hides the API
- Services on RunxBuild
FAQ
Is a 302 redirect bad for SEO?
Not inherently — it is bad when misapplied. A 302 tells search engines the original URL is still canonical, so ranking signals stay with the old URL. For a permanent move that is wrong and costs you the migration. For genuinely temporary redirects it is exactly right.
What is the difference between 302 and 307?
Both are temporary redirects. A 307 guarantees the request method and body are preserved; browsers rewrite POST to GET when following a 302. Use 307 for anything that might receive a non-GET request.
Do browsers cache 302 redirects?
Not by default. A 302 is non-cacheable unless you explicitly add Cache-Control or Expires headers. This is the opposite of 301, which browsers cache aggressively and often permanently.
How do I see the full redirect chain?
Run curl -sIL against the URL and read every HTTP status line and Location header. This shows each hop rather than just the final destination, which is what you need to spot loops and unnecessary hops.
Can a 302 cause a redirect loop?
Yes, usually when two systems disagree about the canonical URL form — an edge rule adding a trailing slash while an application rule strips it, for example. Browsers stop after roughly 20 hops and show an error.