HTTP 302 ステータスコード(302 Found)とは:意味と使い方

Advertisement
HTTP 302ステータスコードとは?
HTTP 302ステータスコード(正式名称:302 Found)は、リクエストされたリソースが一時的に別のURLに移動したことをクライアント(通常はブラウザ)に伝えるHTTPレスポンスコードです。新しいURLはレスポンスのLocationヘッダーで指定され、クライアントは今回のリクエストに限ってそのURLからリソースを取得します。
移動が一時的であるため、クライアントは今後のリクエストでも元のURLを使い続けるべきです。検索エンジン、ブラウザ、ブックマークは元のURLをリダイレクト先で置き換えるべきではありません。これがHTTP 302と301 Moved Permanentlyの最も重要な動作上の違いです。
302コードはRFC 9110で定義されているHTTPステータスコードの3xxリダイレクトクラスに属します。歴史的に「Found」という名前ですが、レスポンスボディはほとんど使われません — 現代のブラウザはLocationヘッダーをレンダリングせずに即座に追従します。
302レスポンスの構造
HTTP 302ステータスコードのレスポンスは常に2つの必須要素を含みます:ステータスライン自体と、新しいURLを指すLocationヘッダーです。有効なLocationヘッダーがないと、クライアントはリダイレクトを追従できません。
ステータスライン —
HTTP/1.1 302 Found(HTTP/2ではHTTP/2 302)Locationヘッダー — クライアントが追従すべき宛先URL(必須)
Cache-Control — 通常は
no-cache。ブラウザがリダイレクト先を永続的にキャッシュしないようにするためボディ — 通常は空。レガシークライアント向けに小さなHTMLページを含める場合もあります(
<html><body><a href="...">こちらをクリック</a></body></html>)
HTTP/1.1 302 Found
Location: https://www.example.com/new-page
Content-Type: text/html; charset=UTF-8
Content-Length: 0
Cache-Control: no-cache, no-store
Date: Mon, 27 Apr 2026 14:00:00 GMTLocationヘッダーは絶対URL(https://example.com/path)でも、パス相対URL(/path)でもかまいません。現代のHTTPクライアントは両方を受け付けますが、明確さのために絶対URLが推奨されます。
302 vs 301 vs 307 vs 308:どのリダイレクトを使うべきか?
HTTPは5つの主要なリダイレクトステータスコードを定義しており、適切なコードの選択はキャッシュ、SEO、リクエストメソッドの保持に影響します。次の表を判断材料に:
| コード | 永続性 | メソッド保持? | ブラウザがキャッシュ? | 最適な用途 |
|---|---|---|---|---|
| 301 Moved Permanently | 永続的 | POST→GETに変わる場合あり | はい(積極的に) | 永続的なURL変更、ドメイン移行 |
| 302 Found | 一時的 | POST→GETに変わることが多い | いいえ | ログインフロー、A/Bテスト、メンテナンス |
| 303 See Other | 一時的 | 常にGETに変わる | いいえ | フォーム送信後のPOST/Redirect/GETパターン |
| 307 Temporary Redirect | 一時的 | はい — 保持される | いいえ | POST/PUTを保持すべき一時リダイレクト |
| 308 Permanent Redirect | 永続的 | はい — 保持される | はい | POST/PUTを保持すべき永続リダイレクト |
現代の推奨:一時リダイレクトが必要でメソッドの扱いを明確にしたいなら、302の代わりに307を使ってください。307コードがHTTP/1.1で追加されたのは、まさに302でブラウザが仕様に反してPOSTをGETに変えていた歴史があり、その誤った動作が事実上の標準になってしまったためです。
302リダイレクトを使うべきタイミング
リダイレクトが本当に一時的な場合 — 将来的にリダイレクト先を削除または変更する予定がある場合 — にHTTP 302ステータスコードを使用します。一般的な正当なユースケース:
ログインリダイレクト — 未認証ユーザーを
/dashboardから/loginへ送り、ログイン後に戻すA/Bテスト — 正規URLを変えずにユーザーの50%をバリアントへルーティング
メンテナンスページ — サーバーパッチ中、すべてのトラフィックを
/maintenanceへ一時リダイレクト地域ルーティング — 訪問者を国に応じて
/から/jpや/usへ送り、/を正規エントリーとして維持モバイルリダイレクト — スマホユーザーを
example.comからm.example.comへ(現在はレスポンシブ設計が好まれる)在庫切れの商品ページ — 商品が再入荷するまで購入者をカテゴリーページへ送る
短期キャンペーンURL —
/black-fridayがセール期間中のみキャンペーンランディングへリダイレクト
これらのいずれかが永続化したら、301に切り替えてください。検索エンジンは長期間続いた302を301として扱うまでに数か月待つため、永続的な移動を302に放置するとその間ランキングシグナルを失います。
Advertisement
302ステータスコードの送信方法
ほとんどのWebサーバーやフレームワークには302リダイレクトを送る組み込みヘルパーがあります。以下が一般的なパターンです。それぞれがHTTP 302 FoundとLocationヘッダーを送信します — 302レスポンスに厳密に必要な要素はこの2つだけです。
Nginx
Nginxではreturnディレクティブをコード302と共に使用します(コードを省略した場合のデフォルトも302):
server {
listen 80;
server_name example.com;
# 一時リダイレクト(302 Found)
location /old-page {
return 302 https://example.com/new-page;
}
}Apache (.htaccess)
ApacheではRedirectを302コードと共に、またはRewriteRuleを[R=302,L]フラグと共に使用します:
# シンプルな一時リダイレクト
Redirect 302 /old-page https://example.com/new-page
# またはmod_rewriteでパターンマッチング
RewriteEngine On
RewriteRule ^maintenance$ /maintenance.html [R=302,L]Node.js (Express)
Expressのres.redirect()はステータスコードを指定しない場合のデフォルトが302です:
// 一時リダイレクト(デフォルトで302 Found)
app.get('/dashboard', (req, res) => {
if (!req.user) {
return res.redirect('/login') // 302を送信
}
// ...ダッシュボードをレンダリング
})
// 明示的に書く場合:
res.redirect(302, '/login')302ステータスコードのテスト方法
302リダイレクトを実装したら、正しく動作するか検証します。最速の方法はターミナルからcurlを使うことです — ブラウザキャッシュの干渉なしに正確なステータスコードとLocationヘッダーが見られます。
# レスポンスヘッダーのみを表示し(-I)、リダイレクトを追従しない
curl -I https://example.com/old-page
# 期待される出力:
# HTTP/2 302
# location: https://example.com/new-page
# cache-control: no-cache
# date: Mon, 27 Apr 2026 14:00:00 GMT
# リダイレクトチェーン全体を追従(-L)し、各ホップを表示
curl -ILs https://example.com/old-page | grep -i 'HTTP/\|location:'ターミナルにアクセスできない場合は、DNS Robotのリダイレクトチェッカーを使って中立的なロケーションからチェーン全体を追跡するか、HTTPヘッダーチェッカーで生のレスポンスヘッダーを確認できます — どちらもブラウザキャッシュをバイパスします。
302リダイレクトとSEO
HTTP 302ステータスコードは検索エンジンに「この移動は一時的なので、元のURLをインデックスに残しておいてください」と伝えます。これはランキングシグナルに直接影響します。
Google Search Centralによると、302は301のように元のURLのランキングシグナルをリダイレクト先に転送しません。元のURLが正規のままです。他の正規化シグナル(内部リンク、サイトマップ、hreflang)が指している場合、Googleは引き続き対象ページをインデックスする可能性がありますが、302自体は正規シグナルではありません。
永続的な移動には301を使う — ドメイン変更、URL構造の変更、ページ統合
一時的な移動には302を使う — ログインフロー、A/Bテスト、メンテナンス、地域ルーティング
永続的な移動を302に放置しない — Googleは長期化した302を301として扱うまで数か月待ち、ランキングエクイティを失います
チェーンを避ける —
A → 302 → B → 302 → Cはシグナルを希釈しページ読み込みを遅らせます。各ホップが遅延を追加します
なぜ302はPOSTリクエストをGETに変えるのか
これはHTTP 302の最も意外な動作です。元のRFCでは、クライアントはリダイレクトを追従する際にリクエストメソッドを保持すべきとされていました。しかしMosaic、Netscape、IEといった初期のブラウザはすべて302でPOSTをGETに変えており、その誤った動作があまりに普及したためWHATWG Fetch Standardで標準化されました。
今日、ブラウザがPOST /loginを送信し、サーバーが302 Foundで応答すると、ブラウザは自動的にリダイレクト先に対してGET /next-pageを発行します。フォームデータは破棄されます。これはサーバー開発者の意図とは異なる場合がほとんどです。
# あなたが送信するもの:
POST /submit-form HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
name=Alice&email=alice@example.com
# サーバーは302で応答:
HTTP/1.1 302 Found
Location: /thank-you
# ブラウザはGETで追従(フォームデータが破棄される!):
GET /thank-you HTTP/1.1
Host: example.comリダイレクトで元のメソッドを保持する必要がある(POSTがPOSTのまま、PUTがPUTのまま)場合は、302ではなく307 Temporary Redirectを使用してください。意図的にボディを破棄してGETに切り替える — 古典的なPOST/Redirect/GETパターン — 場合は303 See Otherを使います。両方とも明確ですが、302は曖昧です。
Advertisement
302の一般的な問題と修正方法
HTTP 302が問題になる場合、通常は次のいずれかの症状として現れます。ほとんどはシンプルな解決策があります:
`200ではなく302が返る` — サーバーが本来リダイレクトすべきでない時にリダイレクトしている。
.htaccess、Nginx設定、フレームワークミドルウェアで意図しないリダイレクトルールを確認`Locationヘッダーのない302` — 無効なレスポンス。ブラウザは空白ページを表示。コードがステータス送信前に
Locationヘッダーを設定していることを確認`自分自身にリダイレクトする302` — リダイレクトループ。
LocationURLがリクエストURLと一致。条件不足のルールを確認`302がフォームデータを破棄する` — POST → 302 → GETでボディが破棄される。POSTを保持するため
307 Temporary Redirectに切り替え`302がブラウザにキャッシュされる` — バグのあるサーバーがリダイレクトに
Cache-Control: max-age=...を設定。Cache-Control: no-cacheを追加し、ブラウザキャッシュをクリア`本番では302、ローカルでは出ない` — 通常はCDNまたはロードバランサーがリダイレクトを追加。オリジンに直接テストして切り分け
302リダイレクトループの診断
リダイレクトループは、URL Aが302をURL Bに返し、URL Bが302をAに返す時に発生します。ChromeとFirefoxでは20ホップ後にブラウザがERR_TOO_MANY_REDIRECTSを表示してあきらめます。
最も多い原因はCDN(Cloudflareなど)とオリジンサーバー間のSSL/HTTPS競合です:CDNがオリジンにHTTPで接続、オリジンがHTTP→HTTPSリダイレクト、CDNがHTTPSを取り除いて再びHTTPで接続 — 無限ループです。
# チェーン全体を追従(無限ループを避けるため10ホップに制限)
curl -ILs --max-redirs 10 https://example.com 2>&1 | grep -i 'HTTP/\|location:'
# ループの例:
# HTTP/2 302
# location: http://example.com/
# HTTP/1.1 302 Found
# Location: https://example.com/
# HTTP/2 302
# location: http://example.com/ <-- ループ確定Locationヘッダーで2つのURLが交互に表示されたら、302リダイレクトループが確定です。完全な修正手順についてはERR_TOO_MANY_REDIRECTSガイドを参照してください。DNS Robotのリダイレクトチェッカーは中立的なロケーションからチェーン全体を追跡し、ループ地点で停止します。
302ステータスコードのベストプラクティス
302 Foundを正しく送信することで、リダイレクト実装でぶつかる多くのバグを回避できます:
常にLocationヘッダーを含める —
Locationのない302は無効で空白ページとしてレンダリングされます常にCache-Control: no-cacheを設定 — そうしないと一部のブラウザがセッション中リダイレクトをキャッシュし、「一時的」の契約を破ります
Locationには絶対URLを使用 —
https://example.com/newは明確;/newは機能しますがホストを変えるプロキシ経由で壊れる可能性リダイレクトは1ホップに留める —
A → 302 → BはOK;A → 302 → B → 302 → Cはページ読み込みを遅らせシグナルを希釈POSTから別ページへ302でリダイレクトしない —
303(意図的なGET)または307(POST保持)を使用毎月リダイレクトを監査 — 古い一時リダイレクトはしばしば理由を超えて生き残ります。リダイレクトチェッカーで確認
移動が永続化したら301に切り替え — 永続的な移動を
302のまま数週間以上放置しない
ブラウザとキャッシュの動作
ブラウザや中継器ごとにHTTP 302の扱いは少しずつ異なります。クセを知っておくとデバッグ時間が節約できます:
| クライアント | 302の既定動作 | キャッシュの既定値 |
|---|---|---|
| Chrome / Edge | 自動追従、POST→GETに変更 | ヘッダー指定がなければキャッシュしない |
| Firefox | 自動追従、POST→GETに変更 | ヘッダー指定がなければキャッシュしない |
| Safari | 自動追従、POST→GETに変更 | リダイレクトのキャッシュがやや積極的 |
| curl(デフォルト) | 追従しない — 302とLocationを表示 | キャッシュなし |
| curl -L | --max-redirs(デフォルト50)まで追従 | キャッシュなし |
| wget(デフォルト) | --max-redirect=20まで自動追従 | キャッシュなし |
| Googlebot | 追従、一時シグナルとして扱う | 元のURLを再クロール |
エッジケース(POSTメソッド、無限ループ、ヘッダー有無)を検証するには、DNS RobotのHTTPヘッダーチェッカーがブラウザによるメソッド書き換えなしに生のレスポンスを表示します。一時リダイレクトについてはMDNドキュメントとRFC 9110仕様もご覧ください。
Advertisement
リダイレクトチェーンを数秒で追跡
DNS Robotの無料リダイレクトチェッカーでチェーンの各ホップを検査 — ステータスコード、Locationヘッダー、最終的な宛先を中立的なサーバーから確認(ブラウザキャッシュなし)。
試す リダイレクトチェッカーAdvertisement
よくある質問
302ステータスコード(HTTP 302 Found)は、リクエストされたリソースが一時的にレスポンスのLocationヘッダーで指定された別のURLにあることを意味します。クライアントは今回のリクエストではリダイレクトを追従しますが、今後のリクエストでも元のURLを使用し続けるべきです。301 Moved Permanentlyの一時的な対応コードです。