HTTP 302 Status Code: What It Means & 302 vs 301

Key takeaway

HTTP 302 Found is a temporary redirect: the server says the page is at another URL for now, given in the Location header. The browser loads that URL at once, while links and search engines keep the original. Use 301 or 308 when a move is permanent; of 20 big sites we checked, none used a 302 for that. You usually meet a 302 when a page needs a login. Browsers turn a POST into a GET when following a 302, so use 307 to keep the method, or 303 after a form.

Check it now

HTTP 302 status code infographic showing temporary redirect flow with Location header and 301 vs 302 vs 307 comparison
HTTP 302 status code infographic showing temporary redirect flow with Location header and 301 vs 302 vs 307 comparison
Start reading
  1. What Is the 302 Status Code?
  2. Anatomy of a 302 Response
  3. Why Am I Getting a 302 Instead of a 200?
  4. 302 vs 301 vs 307 vs 308: Which Redirect Should You Use?
  5. When Should You Use a 302 Redirect?
  6. How to Send a 302 Status Code
  7. How to Test a 302 Status Code
  8. 302 Redirects and SEO
  9. Why a 302 Changes POST Requests to GET
  10. Common 302 Errors and How to Fix Them
  11. 302 Redirect Loops: How to Diagnose
  12. 302 Status Code Best Practices
  13. How Browsers and Tools Handle a 302
  14. Frequently Asked Questions

What Is the 302 Status Code?

HTTP 302 Found is a temporary redirect. The server answers "what you asked for is somewhere else for now" and names the other URL in the Location header. The browser loads that URL straight away, but bookmarks, links and search engines should keep using the original one (RFC 9110 §15.4.3).

That "for now" is the whole difference from 301 Moved Permanently, which says the old URL is gone for good. HTTP/1.0 called 302 "Moved Temporarily" (RFC 1945); RFC 2616 renamed it "Found" in 1999, but the meaning didn't change.

As a visitor you rarely see one, because the browser follows it before anything appears. You meet it in DevTools, in curl, in API clients and in SEO audits.

See every redirect and its status code

Anatomy of a 302 Response

A 302 response is small. Its parts:

  • Status line — HTTP/1.1 302 Found, or just HTTP/2 302 (HTTP/2 has no reason phrase)
  • Location — the URL to go to. RFC 9110 says the server SHOULD send it; without one, the browser has nowhere to go and shows the 302's own body, usually blank
  • Body — RFC 9110 says it "usually contains a short hypertext note" with a link. Browsers ignore it; nginx, Apache and Express send a one-line note by default, while many large sites send an empty body
  • Caching headers — none needed. Browsers don't cache a 302 unless you add Cache-Control: max-age or Expires; 301 and 308, by contrast, are cached by default. A CDN may still cache it (see "A 302 that sticks" below)
http
HTTP/1.1 302 Found
Location: https://www.example.com/login?next=%2Fdashboard
Content-Length: 0
Date: Mon, 26 Oct 2026 14:00:00 GMT

Location can be a full URL or a relative path such as /login: RFC 9110 allows any URI reference, and browsers resolve it against the URL they asked for. In app code (Express, say) a relative path avoids leaking an internal host name or http:// from behind a proxy; nginx and Apache turn it into an absolute URL anyway unless you set absolute_redirect off or RedirectRelative On.

Why Am I Getting a 302 Instead of a 200?

Because the page wants something your request didn't bring, or the URL you used isn't the one the site serves. The usual reasons:

  • You're not signed in — pages behind a login answer 302 to the sign-in page, with the page you wanted in a return parameter. Signed out, github.com/settings sends you to /login?return_to=…. In curl or an API client, send the session cookie or token.
  • Your client doesn't follow redirects — browsers, fetch() and Python's requests follow them automatically. curl doesn't unless you add -L; it stops at the 302 and prints only its body, often nothing (add -i to see the status and Location).
  • The URL isn't the one the site serves — a missing or extra trailing slash, a language path, or a tracking link that bounces you on. Express's res.redirect(), nginx's return with only a URL and Apache's Redirect all send 302 unless told otherwise.
  • Something in front of the server adds it — if the origin answers 200 when you test it directly but the public URL gives 302, a CDN, load balancer or proxy rule is redirecting.

APIs usually answer a missing login with 401 Unauthorized instead of a redirect. To see every hop and its status code, run the URL through the Redirect Checker.

302 vs 301 vs 307 vs 308: Which Redirect Should You Use?

Five redirect codes cover nearly every case. They differ in two ways: whether the move is permanent, and whether a POST stays a POST:

CodePermanent?A POST in browsersCached by default?Best for
301 Moved PermanentlyYesBecomes GETYesPermanent URL changes, domain moves
302 FoundNoBecomes GETNoLogins, short-term moves, A/B tests
303 See OtherNoBecomes GETNoThe page after a form is submitted
307 Temporary RedirectNoStays POSTNoTemporary moves that must keep the method
308 Permanent RedirectYesStays POSTYesPermanent moves that must keep the method

303 and 307 exist because of 302. HTTP/1.1 added 303 in 1997, and in 1999 RFC 2616 admitted that "most existing user agent implementations treat 302 as if it were a 303 response", added 307 and renamed 302 "Found" (RFC 2616 §10.3.3). If a temporary redirect might receive a POST, use 307 to keep it, or 303 to load the next page with a GET.

When Should You Use a 302 Redirect?

Use a 302 when you expect the redirect to go away. Typical cases:

  • Login redirects — sending a signed-out user from /dashboard to /login, then back after sign-in
  • A/B tests — sending some visitors to a variant page; Google's own testing advice says to use 302, not 301, here (Google Search Central)
  • Pages under repair — sending visitors to a notice page for a few days while a page is rebuilt
  • Short-lived campaign URLs — /black-friday pointing at this year's sale page only during the sale
  • Maintenance — for visitors only; for search engines, a 503 with Retry-After is the better answer during planned downtime

If any of these becomes permanent, switch it to a 301.

How to Send a 302 Status Code

Most servers and frameworks have a one-line way to send a 302. Each of these sends 302 Found with a Location header, all a 302 needs.

Nginx

In nginx, use return with the code. return with only a URL also sends a 302 (nginx docs):

nginx
server {
    listen 80;
    server_name example.com;

    # Temporary redirect (302 Found)
    location /old-page {
        return 302 https://example.com/new-page;
    }
}

Apache (.htaccess)

On Apache, use Redirect (302 is its default when you give no status) or a RewriteRule with [R=302,L]:

apache
# Simple temporary redirect
Redirect 302 /old-page https://example.com/new-page

# Or with mod_rewrite for pattern matching
RewriteEngine On
RewriteRule ^maintenance$ /maintenance.html [R=302,L]

Node.js (Express)

Express's res.redirect() defaults to 302 when no status code is provided:

javascript
// Temporary redirect (302 Found by default)
app.get('/dashboard', (req, res) => {
  if (!req.user) {
    return res.redirect('/login') // sends 302
  }
  // ...render dashboard
})

// Or be explicit:
res.redirect(302, '/login')

How to Test a 302 Status Code

The fastest check is curl from a terminal: it shows the status code and Location header with no browser cache in the way.

bash
# Status and headers, without following the redirect
curl -sI https://example.com/old-page

# -I sends HEAD, which some servers answer differently; this sends a real GET
curl -s -o /dev/null -D - https://example.com/old-page

# Expected:
# HTTP/2 302
# location: https://example.com/new-page

# Follow the whole chain and print each hop's status and Location
curl -sL -o /dev/null -D - https://example.com/old-page | grep -iE '^(HTTP/|location:)'

No terminal? DNS Robot's Redirect Checker follows every hop (301, 302, 303, 307, 308 and meta refresh) from our server and shows each status code and the final URL, and the HTTP Header Checker shows each hop's raw headers under Redirects.

302 Redirects and SEO

Google treats the two kinds of redirect as different instructions. For a temporary redirect (302, 303, 307), Googlebot follows it, but Google doesn't take it as a sign that the target should be the canonical URL, so the source page normally stays in search results. The target can still be indexed if other signals point to it (Google Search Central).

A permanent redirect (301, 308) says the opposite: show the new URL. So the real question isn't "does a 302 pass PageRank?" but "which URL do I want in search results?" Your rel=canonical tag is one of the other signals; the Meta Tag Checker shows which URL a page declares.

  • Use 301 or 308 for permanent moves — new domain, new URL structure, merged pages
  • Use 302 for temporary ones — logins, A/B tests, campaigns
  • Don't leave a permanent move on 302 — Google may keep showing the old URL
  • Keep chains short — every hop costs a round trip, and Googlebot follows up to 10 hops by default (Google)

Why a 302 Changes POST Requests to GET

This is the most surprising part of 302. The early specs never let clients change the method, but browsers turned POST into GET on a 302 anyway. Today the Fetch Standard that browsers implement writes the habit down: on a 301 or 302, a POST becomes a GET and its body is dropped (Fetch Standard).

So when a browser sends POST /submit-form and the server answers 302 Found, the browser follows with GET /thank-you, and the form data is gone. Browsers keep PUT and DELETE as they are; other clients differ: Python's requests turns every method except HEAD into a GET on a 302, and curl -L turns a POST into a GET on 301, 302 and 303 (--post302 keeps the POST on a 302).

http
# What you send:
POST /submit-form HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

name=Alice&email=alice@example.com

# Server responds with 302:
HTTP/1.1 302 Found
Location: /thank-you

# Browser follows with GET (form data dropped!):
GET /thank-you HTTP/1.1
Host: example.com

If you need the redirect to preserve the original method (POST stays POST, PUT stays PUT), use 307 Temporary Redirect instead. If you intentionally want to drop the body and switch to GET — the classic POST/Redirect/GET pattern — use 303 See Other. Both are unambiguous; 302 is not.

Common 302 Errors and How to Fix Them

When a 302 goes wrong, it's usually one of these:

  • A 302 instead of a 200 — a login wall, a client that doesn't follow redirects, or a URL variant (see "Why am I getting a 302" above)
  • A 302 with no Location header — nothing can follow it, and the browser shows the 302's own body, usually blank. Set Location before sending the status
  • A 302 that points at itself — a redirect loop: the rule fires on its own target. Add the missing condition
  • A form that loses its data — POST → 302 → GET drops the body. Use 303 to show a result page on purpose, or 307 to keep the POST
  • A 302 that sticks — the server sent Cache-Control: max-age or Expires with it, so browsers cached it, or your CDN cached it (on content Cloudflare caches, it keeps a 302 for 20 minutes unless the headers say otherwise, Cloudflare docs). Remove those headers, purge the CDN and clear the browser cache
  • A 302 in production but not locally — often a CDN, load balancer or proxy rule adding redirects. Test the origin directly to find out

302 Redirect Loops: How to Diagnose

A redirect loop is URL A sending you to B and B sending you back to A. After 20 redirects, the limit in the Fetch Standard, Chrome gives up with ERR_TOO_MANY_REDIRECTS and Firefox with "The page isn't redirecting properly".

A classic cause is Cloudflare's Flexible encryption mode: Cloudflare reaches your server over plain HTTP, your server redirects HTTP to HTTPS, and Cloudflare asks over HTTP again (Cloudflare docs).

bash
# Trace the full redirect chain (limit to 10 hops to avoid infinite loops)
curl -ILs --max-redirs 10 https://example.com 2>&1 | grep -i 'HTTP/\|location:'

# Example of a loop:
# HTTP/2 302
# location: http://example.com/
# HTTP/1.1 302 Found
# Location: https://example.com/
# HTTP/2 302
# location: http://example.com/  <-- loop confirmed

If the same URL keeps coming back in Location, either pointing at itself or two URLs taking turns, you have a loop (with Cloudflare Flexible mode, https://example.com/ redirects to itself). For the full fix, see our ERR_TOO_MANY_REDIRECTS guide. DNS Robot's Redirect Checker traces the chain from our server and stops where it loops.

302 Status Code Best Practices

A few habits avoid most 302 problems:

  • Always send a Location header — without it, nothing follows the redirect
  • Don't add caching headers — a 302 without max-age or Expires isn't cached, which is what you want
  • Mind absolute URLs behind a proxy — in app code a relative /login avoids leaking an internal host name or http:// into Location; nginx and Apache build absolute URLs from their own settings
  • Keep it to one hop — A → B is fine; A → B → C adds a round trip for every visitor
  • Never 302 a POST to a different page — use 303 to show a result page, or 307 to keep the POST
  • Review old temporary redirects — they often outlive their reason. Check them with the Redirect Checker
  • Switch to 301 as soon as a move is permanent

How Browsers and Tools Handle a 302

Clients agree on following a 302 but differ on limits and on what happens to the method:

ClientWhat it does with a 302Redirect limit
Chrome, Edge, Firefox, SafariFollows it at once; a POST becomes a GET20 (Fetch Standard)
fetch() in JavaScriptFollows by default (redirect: "follow"); same POST rule20
curlDoesn't follow; prints only the 302's body, often empty (add -i or -I to see the status and Location)None (no following)
curl -LFollows; a POST becomes a GET on 301, 302 and 303 (--post301, --post302, --post303 keep it)50 (--max-redirs)
wgetFollows20 (--max-redirect)
Python requestsFollows; every method except HEAD becomes a GET30
GooglebotFollows; keeps the source URL as the search result10 hops by default

For the exact wording, see the RFC 9110 definition of 302 and MDN's 302 page.

Trace any redirect chain in seconds

Use DNS Robot's free Redirect Checker to inspect every hop in a redirect chain — see status codes, Location headers, and the final destination from a neutral server (no browser cache).

Sources

  1. RFC 9110: HTTP Semantics, 302 Found, IETF
  2. Fetch Standard: HTTP-redirect fetch, WHATWG
  3. Redirects and Google Search, Google Search Central
  4. Configure cache by status code (default 20 minutes for 302), Cloudflare

Frequently Asked Questions

What does HTTP 302 mean?

HTTP 302 Found is a temporary redirect: the resource is at another URL for now, given in the response's Location header. The browser follows it straight away, but links, bookmarks and search engines should keep using the original URL. Its permanent counterpart is 301 Moved Permanently.

Why am I getting a 302 instead of a 200?

Usually because the page needs a login (it redirects you to the sign-in page), your client doesn't follow redirects (curl needs -L), the URL isn't the exact one the site serves (a trailing slash or language path), or a CDN or proxy rule in front of the server adds a redirect. A redirect checker shows each hop and its status.

Is 302 better than 301?

Neither is better; they say different things. Use 301 (or 308) when a page has moved for good and you want search engines to show the new URL. Use 302 when the move is temporary and the original URL should stay in search results, such as login redirects, A/B tests and campaigns.

Does a 302 redirect hurt SEO?

Not when the move really is temporary. Google follows a 302 but doesn't treat it as a sign that the target should be canonical, so the original URL normally stays in search results. It hurts only when you use it for a permanent move: then Google may keep showing the old URL instead of the new one.

What is the difference between 302 and 307?

Both are temporary redirects. Browsers turn a POST into a GET when following a 302 and drop the body; a 307 keeps the method and body, so a POST stays a POST. Use 307 whenever a temporary redirect might receive a form submission or an API call that isn't a GET.

Why does my POST become a GET after a 302?

Browsers have done it since the 1990s, and the Fetch Standard now requires it: on a 301 or 302, a POST is resent as a GET without its body. Return 307 Temporary Redirect to keep the POST, or 303 See Other if you want the GET on purpose, as in the post/redirect/get pattern after a form.

Are 302 redirects cached by browsers?

Not by default. RFC 9110 doesn't make 302 cacheable without explicit freshness, so browsers cache one only if the server adds Cache-Control: max-age or Expires. A CDN can differ: on content it caches, Cloudflare keeps a 302 for 20 minutes unless the headers say otherwise. 301 and 308 are the opposite: browsers cache them unless told not to.

How do I send a 302 redirect?

Send the status line HTTP/1.1 302 Found plus a Location header with the new URL. In nginx: return 302 https://example.com/new-page; In Apache: Redirect 302 /old https://example.com/new. In Express: res.redirect('/new'), which sends 302 by default.

How do I check if a URL returns a 302?

Run curl -sI https://example.com/your-url in a terminal: it prints the status code and Location without following the redirect. Without a terminal, paste the URL into DNS Robot's free Redirect Checker, which follows every hop and shows each status code and the final URL.

About the author

Shaik Vahid

Founder of DNS Robot. Vahid spent years in web hosting support fixing domains, DNS records, SSL certificates and email delivery for customers. He builds DNS Robot's tools and writes these guides from the errors people actually hit.

Redirect Checker

Follow every redirect hop by hop: 301/302 chains, timing and bulk checks