301・302・303・307・308 の違いを一覧で比較|リダイレクトの使い分け
リダイレクトを設定しようとして、「301 と 302 は聞いたことがあるけれど、303 や 307、308 は何が違うのか」と手が止まった経験はないでしょうか。番号が似ているうえに、どれもブラウザーの画面では「別のページに移動する」という同じ動きに見えます。
ところが、仕様の上では 5 つの番号は役割がはっきり分かれています。見分けるための軸は 3 つだけです。恒久か一時か、メソッドが変わるか、キャッシュされるか。この 3 つを押さえれば、迷う場面はほとんどなくなります。
軸 1: 恒久か一時か
恒久は 301 と 308、一時は 302・303・307 です。
軸 2: メソッド
307 と 308 は変えません。301 と 302 は POST が GET に変わることがあります。
軸 3: キャッシュ
RFC 9110 で、301 と 308 は明示がなくても保存されうる応答です。
迷ったら
恒久なら 301(または 308)、一時なら 302(または 307)、POST の後は 303 です。
5 つもあるせいで起きる、設定ミスの落とし穴
選択肢が多いことは、そのまま間違いやすさにつながります。よくある失敗を挙げます。
- 一時的なつもりで 301 を返してしまう。 301 は保存されうる応答なので、後から元に戻しても、ブラウザーが古い転送先を覚えたままになることがあります。
- フォームの送信先に 302 を使い、データが届かなくなる。 302 を受け取ったクライアントが POST を GET に切り替える実装になっていると、本文が消えて届きません。
- POST の後に 307 を返し、画面を更新するたびに二重送信が起きる。 307 はメソッドを保つため、移動先にも POST が送られます。結果画面を見せたいだけなら 303 が適しています。
- 古いソフトウェアが 308 を理解できない。 308 は 301 や 302 より新しい番号です。RFC 9110 にも、2014 年に定義されたため、一部のソフトウェアは認識しないかもしれない、という注意があります。
どれも、番号の意味を知っていれば避けられるミスです。以降で、軸ごとに整理していきます。
軸 1: 恒久か一時か
もっとも基本となる区別です。
恒久的な移動: 301 と 308
「このリソースは、新しい URL へ恒久的に移りました。今後の参照は新しい URL に切り替えてください」という意味です。サイトの引っ越し、URL 構造の変更、http から https への完全移行などで使います。検索エンジンも、Google 検索セントラルによれば、301 と 308 を「移動先を正規 URL とする強いシグナル」として扱います。
一時的な移動: 302、303、307
「いまは別の場所にあります。ただし、次回以降も元の URL を使ってください」という意味です。メンテナンス中の振り向け、状況によって行き先を変えるアクセス制御などに向いています。
ここで重要なのは、「一時的」とは、あとで元に戻す予定があるということだという点です。戻す予定がないのに 302 や 307 を使い続けると、検索エンジンやクライアントは「元の URL が本体」と解釈し続けます。
「一時的」を長く続けてよいのか
「一時的」の長さに、仕様上の期限はありません。数日で終わる場合も、数年続く場合もあります。大切なのは期間ではなく、元の URL が引き続き正しい住所であるという意図です。たとえば、混雑時だけ別のサーバーへ案内する仕組みや、利用者の地域に応じて行き先を変える仕組みは、元の URL が常に入口として機能するので、長期間 307 を返し続けても問題ありません。逆に、元の URL を使う予定がなくなったのであれば、番号を恒久的なものに切り替えるのが筋です。
恒久か一時かの区別は、サーバーが「この移動を覚えておいてよいか」をクライアントや検索エンジンに伝える手段でもあります。覚えてよい移動には恒久の番号、覚えてほしくない移動には一時の番号を付ける、と考えると整理しやすくなります。
軸 2: メソッドが変わるか
ここが 5 つの違いの核心です。RFC 9110 の記述を整理すると、次のとおりです。
| コード | 自動転送でのメソッド | RFC 9110 の記述の要点 |
|---|---|---|
| 301 | {{status:}} | POST を GET に変えてもよい(MAY) |
| 302 | {{status:}} | POST を GET に変えてもよい(MAY) |
| 303 | {{status:}} | GET(または HEAD)で取得し直す |
| 307 | {{status:}} | 変えてはならない(MUST NOT) |
| 308 | {{status:}} | 変えない |
実際のブラウザーの動作は、WHATWG の Fetch Standard に手順として書かれています。リダイレクトを受け取ったとき、状態コードが 301 または 302 で要求メソッドが POST の場合と、状態コードが 303 でメソッドが GET・HEAD 以外の場合は、メソッドを GET に変え、本文を捨てます。307 と 308 は、この書き換えの対象外です。
POST を GET にしたい(結果を見せたい)
- 303 を使います。
- 注文確定の後に完了ページを表示する、といった用途です。
- 画面を更新しても、二重に送信されません。
POST のまま送りたい(処理を渡したい)
- 307(一時)または 308(恒久)を使います。
- API の書き込み先を切り替える、といった用途です。
- 本文とメソッドが、移動先にもそのまま届きます。
本文を持つ要求の落とし穴
Fetch Standard には、もう一つ見落としやすい規定があります。307 や 308 のように本文を再送する場合、本文がストリームのように一度しか読めない形式だと、再送できずにネットワークエラーとして扱われることがあります。ブラウザーの fetch でストリーム本文を送るような場面では、転送を前提にした設計に注意が必要です。
軸 3: キャッシュされるか
RFC 9110 では、300・301・308 が、明示的な保存期間の指定がなくても保存されうる(ヒューリスティックにキャッシュ可能な)ステータスコードとして整理されています。一方、302・303・307 は、Cache-Control や Expires で保存期間が明示された場合にだけ保存の対象になります。
この違いは、運用に直結します。
- 恒久的な移動(301・308)は、一度ブラウザーに覚えられると、その後の要求はサーバーへ届かず、ブラウザー内で転送が完了することがあります。確認のために何度アクセスしても、サーバーのログに残らない、という現象の正体です。
- 一時的な移動(302・303・307)は、明示がなければ毎回サーバーへ問い合わせるため、設定を変えた結果がすぐ反映されます。
設定を誤って 301 を公開してしまった場合は、ブラウザー側のキャッシュが残るため、修正しても反映が遅れることがあります。迷う段階では、まず一時的な転送で確認し、確定してから恒久的な転送に切り替えるのが、安全な進め方です。
用途別の選び方
目的から逆引きできるように整理します。
| やりたいこと | 選ぶコード | 理由 |
|---|---|---|
| サイトを新ドメインへ引っ越す | 301 | 恒久的な移動。検索エンジンへの強いシグナルになる |
| API の書き込み先を恒久的に変える | 308 | 恒久的で、POST・PUT などのメソッドを保てる |
| メンテナンス中だけ別ページへ案内する | 302 または 307 | 一時的な移動。後で元に戻せる |
| 一時的な移動で、POST を保ちたい | 307 | メソッドと本文を保つ |
| フォーム送信後に完了ページを見せる | 303 | GET で結果ページを取得させる |
| http を https へ強制する(恒久) | 301 または 308 | 恒久的な移動 |
なお、一般的なウェブページ(GET だけで閲覧するもの)の転送であれば、301 と 308、302 と 307 は、利用者から見て同じように動きます。差が出るのは、POST などのメソッドを使う通信です。
3xx の残りの番号も、ざっと確認しておく
リダイレクトの範囲には、ここまで触れなかった番号もあります。
- 300 Multiple Choices: 複数の選択肢があることを示します。実際に使われる場面はごく限られます。
- 304 Not Modified: 転送ではありません。保存してあるデータがまだ新しいので、再取得は不要、という意味です。
- 305 と 306: どちらも現在は使われません。305 は非推奨、306 は欠番です。
実際に設定を行うのは、301・302・303・307・308 の 5 つと考えて差し支えありません。
同じ POST でも、番号しだいで結末が変わる
言葉だけでは違いが実感しにくいので、同じ POST 要求に対して、サーバーが番号を変えて応答した場合の流れを並べます。なお、301 と 302 のメソッド変更は、仕様上は「してもよい」という扱いで、実際の動作はクライアントの実装に依存します。ここでは、Fetch Standard に書かれたブラウザーの手順に沿って示します。
302 を返した場合
clientserver
307 を返した場合
clientserver
303 を返した場合
clientserver
302 と 303 は、どちらも GET に切り替わる点では結果が似ています。ただし、303 は切り替えることが仕様で定められているのに対し、302 は実装しだいで POST のまま送られる可能性が残ります。「GET に切り替えたい」と明確に伝えたいなら、303 が確実です。逆に「POST のまま届けたい」ことを明確に伝えたいなら、307 や 308 を選びます。サーバーの意図を迷わず伝えられることが、番号を使い分ける最大の利点です。
各コードのレスポンス例
最後に、実際に返すヘッダーの例を並べておきます。どの番号でも、移動先を示す Location ヘッダーを添える点は共通です。
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-page
HTTP/1.1 302 Found
Location: https://www.example.com/temporary
HTTP/1.1 303 See Other
Location: https://www.example.com/result
HTTP/1.1 307 Temporary Redirect
Location: https://www.example.com/temporary
HTTP/1.1 308 Permanent Redirect
Location: https://www.example.com/new-page
状態行の文言(Found、Moved Permanently など)は、HTTP/2 以降では伝送されませんが、番号の意味は変わりません。ログや開発者ツールに番号だけが表示されても、上の表と見比べれば意味を取り違えることはありません。
設定したあとの確認手順
どの番号を選んでも、設定したら実際の応答を確認する習慣が大切です。確認の観点は 3 つです。
- 番号が意図どおりか。
curl -Iで、返ってきたステータスコードとLocationを見ます。 - 転送の回数が最小か。
curl -sIL -o /dev/null -w '%{num_redirects} ' URLで回数を確認します。http から https、さらに www の有無を正す、といった複数の転送が重なっている場合は、できるだけ 1 回にまとめると、表示までの時間も短くなります。 - メソッドを使う通信でも期待どおりか。 フォームや API の転送では、
curl -i -X POSTで動作を確かめ、移動先に本文が届いているかをサーバー側のログで見ます。
恒久的な転送(301・308)は、ブラウザーに保存されると取り消しにくくなります。公開前に、一時的な転送で動作を確かめ、問題がなければ恒久的な番号に切り替える流れにしておくと、設定ミスの影響を小さく抑えられます。
迷わないための判断のしかた
最後に、判断を 3 つの質問に落とし込みます。
- 元の URL に戻す予定はありますか。 ない(恒久的)なら 301 か 308、ある(一時的)なら 302・303・307 から選びます。
- POST などのメソッドを使う通信ですか。 使うなら、メソッドを保つ 307 か 308 を選びます。ただし、結果ページを見せたいだけなら 303 です。
- 対象のソフトウェアは新しい番号を理解できますか。 古い環境が混ざる可能性があるなら、301 や 302 のほうが無難な場合があります。
この 3 つを順に確認すれば、ほとんどの場面で答えが出ます。307 の基本は307 Temporary Redirect とはで、302 との違いを深掘りするなら307 と 302 の違いで、恒久的な転送の新しい選択肢は308 Permanent Redirectで、それぞれ詳しく解説しています。