HTTP 302 Foundとは?ステータスコード302の意味と301との違い

ポイント

HTTP 302 Foundは一時的なリダイレクトです。サーバーは「今は別のURLにある」と伝え、そのURLをLocationヘッダーで示します。ブラウザはすぐにそのURLを読み込みますが、リンクや検索エンジンは元のURLを使い続けます。永続的な移転には301か308を使ってください。私たちが確認した大手サイト20件で、そうした移転に302を使っていたところはありませんでした。302に出会うのは、たいていログインが必要なページです。ブラウザは302をたどるときにPOSTをGETに変えるため、メソッドを保つなら307、フォーム送信の後なら303を使います。

今すぐ確認

HTTP 302ステータスコードのインフォグラフィック。Locationヘッダーによる一時リダイレクトの流れと301/302/307の比較
HTTP 302ステータスコードのインフォグラフィック。Locationヘッダーによる一時リダイレクトの流れと301/302/307の比較
読み始める
  1. HTTP 302ステータスコードとは?
  2. 302レスポンスの構造
  3. 200ではなく302が返ってくるのはなぜ?
  4. 302 vs 301 vs 307 vs 308:どのリダイレクトを使うべきか?
  5. 302リダイレクトを使うべきタイミング
  6. 302ステータスコードの送信方法
  7. 302ステータスコードのテスト方法
  8. 302リダイレクトとSEO
  9. なぜ302はPOSTリクエストをGETに変えるのか
  10. 302の一般的な問題と修正方法
  11. 302リダイレクトループの診断
  12. 302ステータスコードのベストプラクティス
  13. ブラウザやツールは302をどう扱うか
  14. よくある質問

HTTP 302ステータスコードとは?

HTTP 302 Foundは一時的なリダイレクトです。 サーバーは「リクエストされたものは今は別の場所にある」と応答し、その移動先のURLをLocationヘッダーで示します。ブラウザはそのURLをすぐに読み込みますが、ブックマークやリンク、検索エンジンは元のURLを使い続けるべきとされています(RFC 9110 §15.4.3)。

この「今は」という点が、古いURLが完全になくなったことを示す301 Moved Permanentlyとの違いのすべてです。HTTP/1.0では302は「Moved Temporarily」と呼ばれていました(RFC 1945)。1999年にRFC 2616で「Found」に改名されましたが、意味は変わっていません。

訪問者として302を目にすることはほとんどありません。画面に何かが表示される前に、ブラウザがたどってしまうからです。302に出会うのは、DevTools、curl、APIクライアント、SEO監査ツールの中です。

すべてのリダイレクトとステータスコードを確認

302レスポンスの構造

302レスポンスはシンプルで、次の要素で構成されます。

  • ステータスライン — HTTP/1.1 302 Found、または単にHTTP/2 302(HTTP/2には「Found」のような理由句がありません)
  • Location — 移動先のURL。RFC 9110では、サーバーはこのヘッダーを送るべき(SHOULD)とされています。ない場合、ブラウザは移動先がわからず302自体のボディを表示し、たいていは空白です
  • ボディ — RFC 9110によれば「通常はリンクを含む短いハイパーテキストの注記」が入ります。ブラウザはこれを無視します。nginx、Apache、Expressはデフォルトで1行の注記を送り、大手サイトの多くは空のボディを返します
  • キャッシュ関連ヘッダー — 不要です。Cache-Control: max-ageやExpiresを付けない限り、ブラウザは302をキャッシュしません。一方、301と308はデフォルトでキャッシュされます。ただしCDNは302をキャッシュすることがあります(後述の「消えない302」を参照)
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には完全なURLも、/loginのような相対パスも使えます。RFC 9110はあらゆるURI参照を認めており、ブラウザはリクエストしたURLを基準に解決します。アプリのコード(Expressなど)では、相対パスにするとプロキシの内側から内部ホスト名やhttp://が漏れるのを防げます。nginxとApacheは、absolute_redirect offやRedirectRelative Onを設定しない限り、いずれにせよ絶対URLに変換して返します。

200ではなく302が返ってくるのはなぜ?

ページが求めるものがリクエストに含まれていないか、使ったURLがサイトの提供しているURLと違うからです。よくある原因は次のとおりです。

  • ログインしていない — ログインが必要なページは、ログインページへの302を返し、見ようとしたページを戻り先のパラメーターに入れます。ログアウトした状態でgithub.com/settingsを開くと、/login?return_to=…に移動します。curlやAPIクライアントでは、セッションCookieかトークンを送ってください。
  • クライアントがリダイレクトをたどらない — ブラウザ、fetch()、Pythonのrequestsは自動でたどります。curlは-Lを付けないとたどらず、302で止まってそのボディだけを出力します。たいていは何も表示されません(ステータスとLocationを見るには-iを付けます)。
  • サイトが提供しているURLではない — 末尾のスラッシュの有無、言語別のパス、別の場所へ転送するトラッキングリンクなどです。Expressのres.redirect()、URLだけを指定したnginxのreturn、ApacheのRedirectは、別のコードを指定しない限りどれも302を返します。
  • サーバーの手前で何かが追加している — オリジンを直接テストすると200なのに、公開URLでは302になる場合は、CDN、ロードバランサー、プロキシのルールがリダイレクトしています。

APIはログインがない場合、リダイレクトではなく401 Unauthorizedを返すのが一般的です。すべてのホップとステータスコードを確認するには、URLをリダイレクトチェッカーにかけてください。

302 vs 301 vs 307 vs 308:どのリダイレクトを使うべきか?

ほぼすべてのケースは5つのリダイレクトコードで対応できます。違いは2点、移動が永続的かどうかと、POSTがPOSTのままかどうかです。

コード永続的?ブラウザでのPOSTデフォルトでキャッシュ?最適な用途
301 Moved PermanentlyはいGETになるはい永続的なURL変更、ドメイン移転
302 FoundいいえGETになるいいえログイン、短期間の移動、A/Bテスト
303 See OtherいいえGETになるいいえフォーム送信後に表示するページ
307 Temporary RedirectいいえPOSTのままいいえメソッドを保つ必要がある一時的な移動
308 Permanent RedirectはいPOSTのままはいメソッドを保つ必要がある永続的な移動

303と307は302がきっかけで生まれたコードです。1997年にHTTP/1.1で303が追加され、1999年のRFC 2616は「既存のユーザーエージェント実装の大半は302を303レスポンスのように扱っている」と認めたうえで、307を追加し、302を「Found」に改名しました(RFC 2616 §10.3.3)。一時的なリダイレクトがPOSTを受け取る可能性があるなら、POSTを保つには307を、次のページをGETで読み込むには303を使ってください。

302リダイレクトを使うべきタイミング

リダイレクトがいずれなくなる見込みのときに302を使います。代表的な例は次のとおりです。

  • ログインリダイレクト — 未ログインのユーザーを/dashboardから/loginへ送り、ログイン後に戻す
  • A/Bテスト — 訪問者の一部をテスト用のページへ送る。Googleのテストに関するガイドも、この場合は301ではなく302を使うよう勧めています(Google検索セントラル)
  • 作り直し中のページ — ページを作り直している数日間だけ、訪問者をお知らせページへ送る
  • 短期キャンペーンのURL — セール期間中だけ/black-fridayを今年のセールページに向ける
  • メンテナンス — 訪問者向けに限ります。検索エンジンに対しては、計画的な停止中はRetry-After付きの503を返すほうが適切です

これらのどれかが永続的なものになったら、301に切り替えてください。

302ステータスコードの送信方法

ほとんどのサーバーやフレームワークでは、302を1行で送れます。以下の例はどれも302 FoundとLocationヘッダーを送ります。302に必要なのはこれだけです。

Nginx

nginxではreturnにコードを付けて使います。URLだけを指定したreturnも302を返します(nginxのドキュメント):

nginx
server {
    listen 80;
    server_name example.com;

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

Apache (.htaccess)

Apacheでは、Redirect(ステータスを指定しなければ302がデフォルト)か、[R=302,L]フラグ付きのRewriteRuleを使います:

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のres.redirect()は、ステータスコードを指定しない場合のデフォルトが302です:

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')

302ステータスコードのテスト方法

いちばん手早いのは、ターミナルでcurlを使う方法です。ブラウザのキャッシュに邪魔されずに、ステータスコードとLocationヘッダーを確認できます。

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:)'

ターミナルがない場合は、DNS Robotのリダイレクトチェッカーが当サーバーからすべてのホップ(301、302、303、307、308、meta refresh)をたどり、各ステータスコードと最終URLを表示します。HTTPヘッダーチェッカーでは、各ホップの生のヘッダーを「リダイレクト」タブで確認できます。

302リダイレクトとSEO

Googleは2種類のリダイレクトを別々の指示として扱います。一時的なリダイレクト(302、303、307)の場合、Googlebotはリダイレクトをたどりますが、Googleはそれをリダイレクト先が正規版であることを示すシグナルとしては使いません。そのため、通常はリダイレクト元のページが検索結果に残ります。ほかのシグナルがリダイレクト先を指していれば、リダイレクト先がインデックスに登録されることもあります(Google検索セントラル)。

永続的なリダイレクト(301、308)はその逆で、「新しいURLを表示してほしい」という意味です。つまり本当の問題は「302はPageRankを渡すのか?」ではなく、「検索結果にどのURLを表示したいか?」です。rel=canonicalタグも、そのほかのシグナルの一つです。ページがどのURLを宣言しているかはメタタグチェッカーで確認できます。

  • 永続的な移動には301か308 — 新しいドメイン、新しいURL構造、ページの統合
  • 一時的な移動には302 — ログイン、A/Bテスト、キャンペーン
  • 永続的な移動を302のまま放置しない — Googleが古いURLを表示し続けることがあります
  • チェーンは短く — ホップごとに往復が1回増えます。また、Googlebotはデフォルトで最大10回のリダイレクトホップをたどります(Google)

なぜ302はPOSTリクエストをGETに変えるのか

302でいちばん意外な点です。初期の仕様はクライアントがメソッドを変えることを一度も認めていませんでしたが、ブラウザは302を受けるとPOSTをGETに変えていました。現在では、ブラウザが実装しているFetch Standardがこの慣習を明文化しています。301か302を受けると、POSTはGETになり、ボディは破棄されます(Fetch Standard)。

そのため、ブラウザがPOST /submit-formを送り、サーバーが302 Foundを返すと、ブラウザは続けてGET /thank-youを送り、フォームのデータは失われます。ブラウザはPUTとDELETEはそのまま保ちます。ほかのクライアントは動作がまちまちで、Pythonのrequestsは302を受けるとHEAD以外のすべてのメソッドをGETに変え、curl -Lは301、302、303でPOSTをGETに変えます(--post302を付けると302でPOSTを保ちます)。

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

リダイレクトで元のメソッドを保つ必要がある(POSTはPOSTのまま、PUTはPUTのまま)なら、307 Temporary Redirectを使ってください。意図的にボディを捨ててGETに切り替える(古典的なPOST/Redirect/GETパターン)なら、303 See Otherを使います。どちらも意味が明確ですが、302はそうではありません。

302の一般的な問題と修正方法

302が問題を起こすときは、たいてい次のどれかです。

  • 200ではなく302が返る — ログインが必要なページ、リダイレクトをたどらないクライアント、URLの表記ゆれのいずれかです(前述の「200ではなく302が返ってくるのはなぜ?」を参照)
  • Locationヘッダーのない302 — たどる先がないため、ブラウザは302自体のボディを表示し、たいていは空白です。ステータスを送る前にLocationを設定してください
  • 自分自身を指す302 — リダイレクトループです。ルールが自分のリダイレクト先でも発動しています。足りない条件を追加してください
  • データが消えるフォーム — POST → 302 → GETでボディが破棄されます。結果ページを意図的に表示するなら303、POSTを保つなら307を使います
  • 消えない302 — サーバーがCache-Control: max-ageやExpiresを付けて送ったためにブラウザがキャッシュしたか、CDNがキャッシュしています(Cloudflareは、キャッシュ対象のコンテンツについて、ヘッダーで別の指定がない限り302を20分間保持します。Cloudflareのドキュメント)。これらのヘッダーを外し、CDNのキャッシュを削除して、ブラウザのキャッシュもクリアしてください
  • 本番だけで出る302 — たいていはCDN、ロードバランサー、プロキシのルールがリダイレクトを追加しています。オリジンを直接テストして確かめてください

302リダイレクトループの診断

リダイレクトループとは、URL AがBへ送り、BがAへ送り返す状態です。Fetch Standardが定める上限の20回を超えると、ChromeはERR_TOO_MANY_REDIRECTSを、Firefoxは「ページの自動転送設定が正しくありません」を表示して読み込みを止めます。

典型的な原因は、CloudflareのFlexible暗号化モードです。Cloudflareは通常のHTTPでサーバーに接続し、サーバーはHTTPをHTTPSへリダイレクトし、Cloudflareは再びHTTPで要求します(Cloudflareのドキュメント)。

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

Locationに同じURLが何度も出てくる場合、つまり自分自身を指しているか2つのURLが交互に出てくる場合は、ループです(CloudflareのFlexibleモードでは、https://example.com/ が自分自身へリダイレクトします)。完全な修正手順はERR_TOO_MANY_REDIRECTSガイドをご覧ください。DNS Robotのリダイレクトチェッカーは当サーバーからチェーンを追跡し、ループする地点で止まります。

302ステータスコードのベストプラクティス

いくつかの習慣で、302の問題の大半は防げます。

  • Locationヘッダーを必ず送る — ないと、何もリダイレクトをたどれません
  • キャッシュ関連ヘッダーを付けない — max-ageもExpiresもない302はキャッシュされません。それが望ましい状態です
  • プロキシの内側での絶対URLに注意 — アプリのコードでは相対パスの/loginにすると、内部ホスト名やhttp://がLocationに漏れません。nginxとApacheは自身の設定から絶対URLを組み立てます
  • 1ホップで済ませる — A → Bは問題ありませんが、A → B → Cはすべての訪問者に往復を1回追加します
  • POSTを302で別のページへリダイレクトしない — 結果ページを表示するなら303、POSTを保つなら307を使います
  • 古い一時リダイレクトを見直す — 理由がなくなった後も残っていることがよくあります。リダイレクトチェッカーで確認しましょう
  • 移動が永続的になったらすぐ301に切り替える

ブラウザやツールは302をどう扱うか

どのクライアントも302をたどりますが、上限とメソッドの扱いが異なります。

クライアント302を受けたときの動作リダイレクトの上限
Chrome、Edge、Firefox、Safariすぐにたどる。POSTはGETになる20(Fetch Standard)
JavaScriptのfetch()デフォルトでたどる(redirect: "follow")。POSTの扱いは同じ20
curlたどらない。302のボディだけを出力し、たいてい空(ステータスとLocationを見るには-iか-Iを付ける)なし(たどらない)
curl -Lたどる。301、302、303でPOSTはGETになる(--post301、--post302、--post303で保持)50(--max-redirs)
wgetたどる20(--max-redirect)
Python requestsたどる。HEAD以外のメソッドはすべてGETになる30
Googlebotたどる。リダイレクト元のURLを検索結果として保持デフォルトで10ホップ

正確な定義は、RFC 9110の302の定義とMDNの302のページをご覧ください。

リダイレクトチェーンを数秒で追跡

DNS Robotの無料リダイレクトチェッカーで、リダイレクトチェーンの各ホップを確認できます。ステータスコード、Locationヘッダー、最終的な移動先を中立なサーバーから表示します(ブラウザのキャッシュの影響なし)。

出典

  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

よくある質問

HTTP 302とはどういう意味ですか?

HTTP 302 Foundは一時的なリダイレクトです。リソースが今は別のURLにあることを示し、そのURLはレスポンスのLocationヘッダーに入っています。ブラウザはすぐにたどりますが、リンクやブックマーク、検索エンジンは元のURLを使い続けるべきとされています。永続的な移動を示す対のコードは301 Moved Permanentlyです。

200ではなく302が返ってくるのはなぜですか?

たいていは、ページにログインが必要(ログインページへリダイレクトされる)、クライアントがリダイレクトをたどらない(curlには-Lが必要)、URLがサイトの提供している正確なURLではない(末尾のスラッシュや言語別のパス)、サーバーの手前のCDNやプロキシのルールがリダイレクトを追加している、のいずれかです。リダイレクトチェッカーを使えば、各ホップとステータスがわかります。

「302エラー」は本当にエラーですか?

いいえ。RFC 9110では、3xxはリダイレクトを表すコードで、エラーは4xx(クライアントエラー)と5xx(サーバーエラー)です。302は、ページが今は別の場所にあることを示すだけです。「302エラー」と呼ばれるのは、リダイレクトがうまく完了しないときです。ログインが必要なページ、リダイレクトをたどらないツール(-Lなしのcurl)、Locationヘッダーのない302、ループするリダイレクトなどが該当します。ループの場合、ChromeはERR_TOO_MANY_REDIRECTSを表示し、Pythonのurllibは「HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop」という例外を出します。どのホップで止まるかは、リダイレクトチェッカーで確認できます。

302は301より優れていますか?

どちらが優れているということはなく、伝える内容が違います。ページが完全に移転し、検索エンジンに新しいURLを表示してほしいときは301(または308)を使います。移動が一時的で、元のURLを検索結果に残したいときは302を使います。ログインのリダイレクト、A/Bテスト、キャンペーンなどがこれに当たります。

302リダイレクトはSEOに悪影響がありますか?

移動が本当に一時的なら、悪影響はありません。Googleは302をたどりますが、リダイレクト先が正規版であるべきというシグナルとしては扱わないため、通常は元のURLが検索結果に残ります。問題になるのは永続的な移動に302を使った場合だけで、その場合はGoogleが新しいURLではなく古いURLを表示し続けることがあります。

302と307の違いは何ですか?

どちらも一時的なリダイレクトです。ブラウザは302をたどるときにPOSTをGETに変えてボディを破棄しますが、307はメソッドとボディを保つので、POSTはPOSTのままです。一時的なリダイレクトがフォーム送信やGET以外のAPI呼び出しを受ける可能性があるなら、307を使ってください。

なぜ302リダイレクトの後、POSTリクエストがGETになるのですか?

ブラウザは1990年代からそう動作しており、現在ではFetch Standardがそれを義務づけています。301か302を受けると、POSTはボディなしのGETとして送り直されます。POSTを保つには307 Temporary Redirectを、フォーム送信後のPOST/Redirect/GETパターンのように意図的にGETにしたい場合は303 See Otherを返してください。

302リダイレクトはブラウザにキャッシュされますか?

デフォルトではキャッシュされません。RFC 9110では、明示的な有効期限がない302はキャッシュ可能になりません。そのため、ブラウザがキャッシュするのはサーバーがCache-Control: max-ageかExpiresを付けた場合だけです。CDNは別で、Cloudflareはキャッシュ対象のコンテンツについて、ヘッダーで別の指定がない限り302を20分間保持します。301と308は逆で、指定がなければブラウザがキャッシュします。

302リダイレクトはどうやって送りますか?

ステータスライン HTTP/1.1 302 Found と、新しいURLを入れたLocationヘッダーを送ります。nginxでは return 302 https://example.com/new-page; 、Apacheでは Redirect 302 /old https://example.com/new 、Expressでは res.redirect('/new') を使います。Expressはデフォルトで302を送ります。

URLが302を返すかどうかはどう確認しますか?

ターミナルで curl -sI https://example.com/your-url を実行してください。リダイレクトをたどらずに、ステータスコードとLocationを表示します。ターミナルがなければ、URLをDNS Robotの無料リダイレクトチェッカーに貼り付けてください。すべてのホップをたどり、各ステータスコードと最終URLを表示します。

著者について

Shaik Vahid

DNS Robot 創設者. Vahid は長年 Web ホスティングのサポートで、お客様のドメイン、DNS レコード、SSL 証明書、メール配信の問題を解決してきました。DNS Robot のツールを開発し、実際によく起きるエラーをもとにこれらのガイドを書いています。

リダイレクトチェッカー

SEO向けにURLリダイレクト、リダイレクトチェーン、HTTPステータスコードを確認