307 Temporary Redirect
Redirect
The target resource resides temporarily at a different URI and the client must not change the request method when following the redirect. 307 was added in HTTP/1.1 specifically to remove the ambiguity of 302. Where most clients silently downgrade POST to GET, 307 requires the client to preserve the original method, headers, and body. This makes 307 the correct temporary redirect for APIs and any non-GET request.
When does this happen?
Use 307 when you need a temporary redirect that preserves the HTTP method. The clearest signal that 307 is the right choice is when the original request had a body. A POST, PUT, PATCH, or DELETE. With 307 the client will reissue the same method against the new URL with the original body intact. The classic HSTS scenario is the Chrome internal upgrade: when a Chromium-based browser has cached an HSTS policy for a domain, it rewrites http:// to https:// before sending and surfaces the rewrite as a synthetic '307 Internal Redirect' row in DevTools (with a Non-Authoritative-Reason: HSTS header). Firefox and Safari perform the same upgrade silently and do not emit a redirect entry in their network panels. Other uses include load balancers temporarily routing traffic to a different backend, API gateways relocating endpoints during deploys, and edge functions that need to bounce a request to a different region while keeping the body. Like 302, 307 is not cached aggressively by browsers and search engines do not transfer ranking signals through it.
Common causes
- HSTS upgrade. The browser had a Strict-Transport-Security entry for the domain and upgraded http:// to https:// internally; Chromium surfaces this as a synthetic 307 row in DevTools, while Firefox and Safari upgrade silently.
- API gateway routing POST /v1/foo to a temporarily different upstream while keeping the body intact.
- Load balancer draining a backend pool. In-flight requests are 307-redirected to the new pool with their original methods.
- Edge function that needs to bounce traffic to a different region without losing the request body.
- Maintenance window for a specific API endpoint where the temporary fallback handler lives at a different path.
- Older HTTP/1.0 clients receiving 302 may downgrade POST to GET. Switching to 307 fixes the bug without changing semantics.
How to fix it
- If the move is permanent, switch to 308. Using 307 forever leaves the original URL canonical for search engines and breaks consolidation of link equity.
- Verify clients actually preserve the method. Some very old libraries (curl prior to 308 support in 7.49, ancient .NET) still incorrectly downgrade to GET on 307/308. Test with the real client stack.
- Confirm the new URL accepts the original method. A 307 to a GET-only endpoint will fail at the destination.
- When using 307 for HSTS upgrades, ensure the HTTPS endpoint serves the same resource. The internal redirect bypasses HTTP entirely so the HTTPS handler must be correct.
- Watch for redirect loops. A 307 that points back at the original URL via a different path creates an infinite cycle that clients abort after a handful of hops.
- Document the 307 behavior in your API spec so client implementers know the redirect preserves the body.
Real-world examples
- Browser navigates to http://example.com and the domain has an HSTS policy from a previous HTTPS visit.
- Browser internally rewrites the URL to https://example.com without touching the network. Chrome shows a synthetic '307 Internal Redirect' row in DevTools; Firefox and Safari upgrade silently with no extra entry.
- API client issues POST /v1/uploads with a 10MB body and the gateway is routing /v1/uploads to a temporary upstream.
- Gateway returns 307 with Location: /tmp-uploads. Client reissues POST /tmp-uploads with the same body. The upload completes normally.
- Edge function routes a POST to a different region while the home region is failing over.
- Edge returns 307 with Location pointing at the failover region. Client preserves method and body and the request completes in the new region.
- Load balancer drains pool A and redirects in-flight traffic to pool B.
- LB returns 307 to clients with Location at pool B's endpoint. Clients reissue with the original method and the operation completes without data loss.
Debugging
- Run curl -I -X POST https://example.com/v1/endpoint -d 'payload' and confirm 307 is returned with a Location header.
- Use curl -L --post301 --post302 --post303 to force curl to preserve POST through any redirect chain when reproducing client behavior.
- In Chrome DevTools Network tab, identify whether the 307 is a synthetic 'Internal Redirect' (HSTS) row. Those never hit the network and are not real server responses. Firefox and Safari don't render this synthetic row, so the HSTS upgrade is invisible in their network panels.
- Inspect the second request after the 307 and confirm the Request Method matches the first request. If it changed, the client is non-conforming.
How it differs from related codes
HTTP 302
302 is the legacy temporary redirect that most clients downgrade to GET. 307 is the strict-method version. Required for any request with a body you care about preserving.
HTTP 308
308 is permanent, 307 is temporary. Both preserve the method. Use 308 when search engines and clients should treat the new URL as canonical; use 307 when the move may be reversed.
HTTP 301
301 is permanent and historically allowed method downgrade. 307 is temporary and forbids method downgrade. The pairings are 301↔308 (permanent) and 302↔307 (temporary).
Related status codes
See HTTP 307 in your redirect chains?