< HTTP/1.1 302 FoundHTTP 302 Found: Temporary Redirect
Learn what 302 redirect means, when to use temporary vs permanent redirects, and how 302 differs from 301, 307, and 308.
- Cacheable
- Only with explicit freshness
- Client action
- Follow Location for this request only
- Usually sent by
- Origin app, reverse proxy or CDN rule
- Spec
- RFC 9110 §15.4.3
On this page
TL;DR: 302 Found means the requested URL temporarily redirects to another URL. Follow
Location; if the redirect is unexpected or loops, inspect the first response and the rule that sends it. Use 307 when the request method and body must survive.
What it means
The HTTP exchanges below are illustrative. A request to /promo receives a temporary destination in Location.
GET /promo HTTP/1.1
Host: example.com
HTTP/1.1 302 Found
Location: /current-sale
302 is not heuristically cacheable. Explicit freshness such as Cache-Control: max-age=600 can make a GET redirect reusable for ten minutes (RFC 9111 section 4.2.2). Express’s res.redirect('/x') defaults to 302; pass a status explicitly for a permanent move.
What you see in your client
An HTTP 302 is a redirect response. Automatic following can hide it behind the destination’s status, so inspect the first response when your browser and script appear to disagree.
- Axios: in Node’s HTTP adapter,
maxRedirects: 0exposes the redirect. With the default success predicate, it rejects withAxiosError: Request failed with status code 302. Accept the code invalidateStatusto inspectresponse.headers.location. The behavior comes from the HTTP adapter, defaults and error construction. - Browser fetch: follows redirects by default and returns the final response. With
redirect: 'manual', a browser returnstype: 'opaqueredirect',status: 0andok: false, with hidden headers. A directly exposed 302 would also haveok: false, since only 200–299 passes. Use the Network panel or curl for the actualLocation; these rules are in the Fetch Standard. - Python requests:
requests.get(url, allow_redirects=False)exposes 302;raise_for_status()returns normally andresponse.okisTrue. Inspectresponse.headers['Location']. Its error guard raises for 4xx/5xx, while GET follows by default. - curl
-f: accepts 302;-Lenables following. Without-L, inspect the headers using-i. The manual reserves failure code 22 for HTTP responses of 400 or greater. - .NET: set
HttpClientHandler.AllowAutoRedirect = falseto inspect the first response. CallingEnsureSuccessStatusCode()then throwsHttpRequestException; with English resources and reason phraseFound, the message isResponse status code does not indicate success: 302 (Found).See the redirect setting, guard and message resources. - Spring:
WebClient.retrieve()usesWebClientResponseExceptionfor 4xx/5xx by default.RestTemplate’s default handler likewise treats those ranges as errors; a 302 alone produces neither that exception norHttpClientErrorException.
Which temporary redirect?
| Situation | Use | Why |
|---|---|---|
| After a form POST, send the user to a result page | 303 | Always becomes GET; the precise code for Post/Redirect/Get |
| Temporary move and the method/body must survive | 307 | POST stays POST |
| Plain GET page redirected temporarily | 302 | Works everywhere; method change is harmless for GET |
RFC 9110 allows POST to become GET on 302. The Fetch redirect algorithm makes that change for browser requests; 307 preserves the method and body. See 302 vs 307.
Implementation
Express
// Login redirect: encode user input and keep the target on-site
app.get('/dashboard', (req, res, next) => {
if (!req.user) {
return res.redirect(302, `/login?returnTo=${encodeURIComponent(req.originalUrl)}`)
}
next()
})
// After login: validate returnTo before redirecting (open-redirect defense)
app.post('/login', (req, res) => {
const target = String(req.query.returnTo || '/')
const safe = target.startsWith('/') && !target.startsWith('//') && !target.startsWith('/\\')
res.redirect(303, safe ? target : '/')
})
An unvalidated returnTo lets an attacker craft https://yoursite.com/login?returnTo=https://evil.example, which turns your domain into a phishing launchpad. Allow only same-site relative paths or an explicit allowlist of hosts.
nginx
location = /promo {
return 302 /current-sale;
}
Common causes by stack
Express: res.redirect('/login') defaults to 302. Check authentication middleware when an API suddenly returns a login page; use an API’s documented authentication response instead of sending its client through an HTML login flow.
Django: redirect('/login/') defaults to 302. Check the view or authentication wrapper that chooses the target. Use permanent=True for a permanent move; use preserve_request=True when the method/body must remain intact, which selects 307 for a temporary redirect.
Laravel: redirect()->to('/dashboard') uses 302 by default; the Redirector source declares $status = 302. Trace that response call when a successful form POST appears as “302 Found” in the Network panel, then inspect the following GET.
Rails: redirect_to defaults to 302. Set status: :see_other after a form mutation when the destination is a result page, and inspect the session cookie if the destination sends the user straight back to login.
nginx / Apache: nginx’s return 302 /current-sale; explicitly emits the temporary redirect. Apache’s Redirect /promo /current-sale uses 302 when the status is omitted. Inspect the loaded virtual host or location for a matching rule before changing application code.
AWS ALB: a listener redirect action with StatusCode: HTTP_302 returns 302 before the request reaches a target. Check the matching listener rule and its protocol, host, port and path substitutions; at least one must change to avoid a loop.
Kubernetes ingress-nginx: nginx.ingress.kubernetes.io/temporal-redirect returns 302 instead of forwarding to the upstream. Inspect that Ingress annotation when the application’s logs show no request.
FastAPI’s Starlette RedirectResponse defaults to 307, so a FastAPI 302 requires an explicit status or another layer’s redirect rule. Inspect RedirectResponse(url, status_code=302) before attributing the response to the framework’s default.
SEO behavior
Google follows a 302 but does not use that temporary redirect to select the destination as canonical. Other canonicalization signals can affect which URL appears in search. Use 301 or 308 for a permanent move, and retain 302 for a destination you expect to revert.
Debugging
curl -sI https://example.com/promo
curl -sIL -o /dev/null -w '%{http_code} -> %{url_effective}\n' https://example.com/promo
# See what a POST turns into (curl -L switches POST to GET on 301/302/303 unless --post302)
curl -si -L -d 'a=1' https://example.com/form
Chrome reports ERR_TOO_MANY_REDIRECTS when a chain loops. Inspect cookies during a repeated dashboard-to-login bounce; for a scheme loop, compare the edge and origin HTTPS rules. Cloudflare documents loops caused by Flexible mode and origin HTTPS redirects. Trace the chain with the redirect audit tool.
Inspect a redirect without following it
For an API call, use curl -si with the actual request method and body, then read Location before enabling -L. A HEAD probe with -I can exercise a different route from your POST. Repeat the request with -L -v to inspect the outgoing methods in a test environment.
In the command above, -d selects POST. Adding -X POST would force that method string on subsequent requests with -L, masking the normal POST-to-GET change. Use --post302 only when deliberately testing curl’s method-preserving behavior; the curl manual distinguishes it from the default.
Post/Redirect/Get
PRG makes a result-page reload repeat a GET instead of submitting the original POST again. The server handles the POST, then redirects the browser to a GET page; reloading that page repeats only the GET. Fetch changes POST to GET on 302, but 303 states the intended retrieval explicitly (RFC 9110 section 15.4.4).
POST /posts HTTP/1.1
Host: example.com
Content-Length: 0
HTTP/1.1 303 See Other
Location: /posts/123
Related
Frequently asked questions
What does 302 redirect mean?
A 302 tells browsers the resource is temporarily at a different URL. Keep using the original URL—it will work again later.
What is the difference between 301 and 302?
301 marks a permanent move and gives Google a strong canonicalization signal. 302 marks a temporary move, so clients should keep using the original URL for future requests.
Does 302 affect SEO?
Google follows 302 redirects but does not use them to select the destination as canonical. Use 301 or 308 when the move is permanent and the destination should become canonical.
When should I use 302 vs 307?
Browsers using Fetch change POST to GET when following 302. 307 guarantees method preservation, and 303 is the explicit choice for redirecting a POST to a GET result page.
Sources
Related
301 vs 302 Redirects
Understand the difference between 301 Moved Permanently and 302 Found redirects. Learn when to use each, how browsers cache them, and their SEO implications.
302 vs 307 Redirects
Compare 302 Found and 307 Temporary Redirect, including method preservation, request bodies, browser behavior, caching, and safe API redirect choices.
300 Multiple Choices
The request has multiple possible responses. Learn when to use 300 Multiple Choices for content negotiation and alternative resource locations.
303 See Other
Redirect to a different resource using GET. Learn when to use 303 to prevent form resubmission and implement the Post-Redirect-Get pattern.
307 Temporary Redirect
Temporary redirect that preserves the HTTP method. Learn when to use 307 instead of 302 for method-sensitive redirects.
308 Permanent Redirect
Permanent redirect that preserves the HTTP method. Learn when to use 308 instead of 301 for method-sensitive permanent redirects.