HTTPリダイレクトは、サーバーがブラウザやAPIクライアントに対して「このURLではなく、別のURLへ移動してください」と伝えるレスポンスです。移動先は主に Location ヘッダーで示されます。301や308は恒久的な移動、302や307は一時的な移動に使われ、303はPOST後にGETで結果ページへ移動させる場面でよく使われます。ステータスコードごとの違いを理解すると、URL変更、ログイン後遷移、フォーム送信後の画面遷移を安全に設計しやすくなります。

1. HTTPリダイレクトとは何か
1-1. 別URLへ移動してもらうレスポンス
HTTPリダイレクトとは、サーバーがクライアントに別URLへ移動してもらうためのレスポンスです。ブラウザでページを開いたとき、サーバーが「このページではなく、こちらへ移動してください」と返す仕組みです。
通常のレスポンスでは、HTMLやJSONなどの本文を返します。一方、リダイレクトでは、本文そのものを見せるよりも、別のURLへ再リクエストしてもらうことが目的になります。ブラウザはリダイレクトレスポンスを受け取ると、指定されたURLへ自動でアクセスすることが多いです。
たとえば、/old-page へアクセスした人を /new-page へ移動させる、ログイン後にマイページへ移動させる、フォーム送信後に完了画面へ移動させる、といった場面で使われます。単なる画面遷移ではなく、HTTPレスポンスとして移動を指示する仕組みだと理解すると整理しやすいです。
1-2. Locationヘッダーの役割
リダイレクトでは、Location ヘッダーで移動先URLを伝えるのが基本です。ステータスコードだけでは、どこへ移動すればよいか分かりません。
サーバーは、301、302、303、307、308などのリダイレクト系ステータスコードと一緒に、Location ヘッダーを返します。ブラウザはこのヘッダーを見て、次にアクセスするURLを決めます。つまり、ステータスコードは「どういう種類の移動か」、Locationは「どこへ移動するか」を表します。
“`http id=”s3p2k1″
HTTP/1.1 302 Found
Location: /login
この例では、一時的に `/login` へ移動するように伝えています。注意点は、Locationが間違っていると意図しないページへ飛んだり、同じURLへ戻ってリダイレクトループになったりすることです。ステータスコードだけでなく、移動先URLも必ず確認しましょう。
### 1-3. 画面遷移、URL変更、フォーム送信で使われる理由
リダイレクトは、**画面遷移、URL変更、フォーム送信後の再表示防止などで使われます**。リンク移動だけでは対応しにくいサーバー側の判断を反映できるからです。
たとえば、未ログインのユーザーがマイページへアクセスしたらログイン画面へ移動させる、古いURLへ来たユーザーを新しいURLへ案内する、POSTで登録したあと完了ページへ移動させる、といった使い方があります。サーバー側が状態を見て移動先を決められるため、認証やフォーム処理と相性がよいです。
ただし、すべての画面遷移をリダイレクトで行えばよいわけではありません。単純なフロント側のページ切り替え、APIレスポンスとしてJSONを返すべき処理、恒久的なURL変更など、目的によって適した方法やステータスコードが変わります。
## 2. 301と302の違い
### 2-1. 301は恒久的な移動
301は、**リソースが恒久的に別URLへ移動したことを伝えるリダイレクト**です。古いURLを今後も新しいURLへ置き換えたい場合に使います。
恒久的な移動とは、「このURLはもう新しいURLへ変わりました」という意味です。ブラウザや検索エンジンは、301を受け取ると新しいURLを強く正規のURLとして扱うことがあります。そのため、サイト移転やURL設計の変更、HTTPからHTTPSへの移行などで使われます。
http id=”a7lq9e”
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-page
この例では、旧URLから新URLへ恒久的に移動したことを伝えています。注意点は、一時的なキャンペーンページやログイン判定に301を使わないことです。ブラウザや検索エンジンに強く記憶される可能性があるため、あとで戻したい移動には向きません。
### 2-2. 302は一時的な移動
302は、**一時的に別URLへ移動させたいときに使うリダイレクト**です。元のURL自体は今後も有効なまま、今だけ別の場所へ案内したい場合に向いています。
たとえば、未ログイン時にログイン画面へ移動させる、メンテナンス中だけ別ページへ移動させる、ABテストで一時的に別ページへ振り分ける、といった場面です。302は「移動先は一時的なので、元のURLも引き続き使います」という意味を持ちます。
http id=”npv1rh”
HTTP/1.1 302 Found
Location: /maintenance
この例では、一時的にメンテナンスページへ移動しています。注意点は、恒久的なURL変更にも302を使い続けると、検索エンジンや利用者に新しいURLが正規だと伝わりにくいことです。一時なのか恒久なのかを先に決めて使い分けましょう。
### 2-3. SEOやブックマークへの影響
301と302の違いは、**SEOやブックマーク、キャッシュの扱いにも影響します**。単に「どちらも移動できるから同じ」と考えるのは危険です。
301は恒久的な移動なので、検索エンジンは新しいURLを正規のURLとして扱いやすくなります。利用者のブックマークや外部リンクを新URLへ寄せたいときにも向いています。一方、302は一時的な移動なので、元のURLを残したい場合に使います。検索エンジンへ「今だけ別の場所です」と伝える意味合いになります。
たとえば、記事URLを完全に変更したなら301が候補です。ログインしていないユーザーだけログインページへ飛ばすなら302が自然です。SEO目的のURL変更と、アプリの状態による一時遷移を混ぜないことが重要です。
## 3. 303、307、308の違い
### 3-1. 303はPOST後にGETへ切り替えたい場面で使う
303は、**POSTなどの処理後に、GETで別ページへ移動させたいときに使うリダイレクト**です。フォーム送信後の完了画面へ移動する場面でよく使われます。
POSTで登録や更新を行ったあと、そのまま同じURLを再読み込みすると、フォームが再送信される可能性があります。303を使うと、クライアントに「処理結果は別URLへGETで取りに行ってください」と伝えられます。これにより、送信処理と結果表示を分けやすくなります。
http id=”e6v3td”
HTTP/1.1 303 See Other
Location: /users/complete
この例では、POST後に `/users/complete` をGETで表示するように案内しています。注意点は、303は「同じメソッドで再送してほしい」場面には向かないことです。POSTのまま別URLへ送る必要があるなら、307や308の考え方が関係します。
### 3-2. 307は一時的な移動だがメソッドを維持する
307は、**一時的なリダイレクトであり、元のHTTPメソッドを維持する**ステータスコードです。POSTならPOSTのまま、PUTならPUTのまま移動先へ再リクエストします。
302では、歴史的な経緯により、クライアントがPOSTをGETに変えて再リクエストすることがあります。これに対して307は、メソッドとリクエスト本文を維持することを明確にします。つまり、「一時的に別URLへ送るが、リクエストの意味は変えないでほしい」というときに使います。
http id=”td0fy1″
HTTP/1.1 307 Temporary Redirect
Location: /temporary-upload-endpoint
この例では、一時的に別のアップロード先へ移動させつつ、元のメソッドを維持する意図があります。注意点は、POSTの本文も再送される可能性があることです。フォーム送信後に完了画面を表示したいだけなら、307ではなく303のほうが分かりやすい場面が多いです。
### 3-3. 308は恒久的な移動だがメソッドを維持する
308は、**恒久的なリダイレクトであり、元のHTTPメソッドを維持する**ステータスコードです。301に似ていますが、メソッドを変えない点が明確です。
301は恒久的な移動を表しますが、クライアントによってはPOSTをGETへ変える挙動が問題になることがあります。308は、恒久的な移動でありながらメソッドと本文を維持することを示します。APIエンドポイントの恒久移動など、メソッドの意味を変えたくない場面で候補になります。
http id=”duwyiq”
HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/v2/items
この例では、APIの移動先を恒久的に示しつつ、メソッド維持を期待しています。注意点は、ブラウザ画面遷移や通常のページ移転では301のほうが見慣れている場面も多いことです。308は便利ですが、POSTやPUTなどのメソッド維持が本当に必要かを考えて使いましょう。
## 4. POST後リダイレクトの基本
### 4-1. フォーム再送信を防ぐPRGパターン
POST後の画面遷移では、**PRGパターンを使うとフォーム再送信を防ぎやすくなります**。PRGは、Post、Redirect、Getの流れを表します。
フォーム送信でPOSTしたあとに、そのまま完了画面を返すと、ユーザーがブラウザ更新したときにPOSTが再送信されることがあります。これにより、二重登録や二重注文の原因になる場合があります。PRGパターンでは、POSTで処理を行い、リダイレクトで結果ページへ移動し、最後はGETで表示します。
たとえば、お問い合わせフォームでは、POSTで問い合わせを登録したあと、303で完了画面へ移動させます。ユーザーが完了画面で更新してもGETが再実行されるだけなので、同じ問い合わせが再送信されにくくなります。
### 4-2. 登録完了画面やログイン後遷移の例
登録完了画面やログイン後遷移では、**処理と表示を分けるためにリダイレクトがよく使われます**。これはユーザー体験と安全性の両方に関わります。
ユーザー登録では、POSTで登録処理を実行し、成功したら完了画面へ移動します。ログインでは、POSTで認証処理を行い、成功したらマイページや元々見ようとしていたページへ移動します。こうすると、処理用URLと表示用URLを分けられるため、画面更新時の再送信や不自然なURL表示を減らせます。
http id=”47bnf4″
HTTP/1.1 303 See Other
Location: /mypage
“`
この例では、ログイン処理後にGETでマイページへ移動させる意図があります。注意点は、ログイン後の移動先をユーザー入力から受け取る場合、外部サイトへ自由に飛ばせないように検証することです。意図しないオープンリダイレクトを防ぐ必要があります。
4-3. 302で済ませる場合と303を使う場合
POST後のリダイレクトでは、実務上302で動く場面もありますが、GETへ切り替えたい意図を明確にするなら303が分かりやすいです。
多くのブラウザでは、POST後の302で移動先へGETする挙動が見られます。そのため、昔からフォーム送信後に302を使う実装もあります。ただし、302は本来「一時的な移動」を示すもので、POST後にGETへ切り替える意図を明示するなら303のほうが意味がはっきりします。
初心者のうちは、フォーム送信後に結果ページを表示したいなら303、未ログイン時にログインページへ一時的に飛ばしたいなら302、と分けて覚えると実装意図を説明しやすくなります。既存フレームワークが302を使うこともあるため、挙動と意味の両方を確認しましょう。
5. よくある落とし穴
5-1. 恒久移動に302を使い続ける
恒久的なURL変更に302を使い続けると、新しいURLが正規のURLだと伝わりにくくなることがあります。これはSEOや運用面で問題になりやすいです。
302は一時的な移動を表します。そのため、古いURLはまだ有効で、今だけ別URLへ案内しているという意味になります。もしサイト構造を変更してURLが完全に変わったなら、301や場合によっては308のような恒久リダイレクトを検討します。
たとえば、/blog/old-title を完全に /blog/new-title へ変更したのに302のままだと、検索エンジンや外部リンクの評価が新URLへ移りにくい可能性があります。一時的な変更か恒久的な変更かを決めてからステータスコードを選びましょう。
5-2. POSTのメソッド維持を考えずに307/308を使う
307や308を使うときは、POSTやPUTなどのメソッドが維持されることを理解しておく必要があります。ここを知らないと、意図しない再送信につながります。
307は一時的、308は恒久的なリダイレクトですが、どちらも元のメソッドを維持します。つまり、POSTリクエストが307で別URLへ移動すると、移動先にもPOSTが送られます。これはAPI移動では便利な場合がありますが、フォーム送信後に完了画面へ移動したい場面では不向きです。
たとえば、ユーザー登録POSTのあとに307で完了ページへ移動させると、完了ページへPOSTが飛ぶ可能性があります。完了画面をGETで表示したいなら303を検討しましょう。メソッドを維持したいのか、GETへ切り替えたいのかを先に決めることが大切です。
5-3. リダイレクトループを起こす
リダイレクトループは、移動先でまた元のURLや同じ条件へリダイレクトしてしまう問題です。ブラウザで「リダイレクトが多すぎます」と表示される典型的な原因です。
たとえば、未ログインなら /login へ飛ばす処理があるのに、/login 自体にも同じ未ログインチェックをかけてしまうと、ログインページへ入れずループします。また、HTTPからHTTPSへ飛ばす設定と、逆向きの設定が同時にある場合もループします。つまり、条件分岐と移動先の組み合わせを間違えると発生します。
対策としては、リダイレクト対象外のURLを明確にする、認証前でも見られるページを分ける、プロキシやロードバランサの設定も含めて確認する、などがあります。ループが起きたら、DevToolsのNetworkタブでどのURLを行き来しているかを見ると切り分けやすいです。
6. まとめ
6-1. リダイレクトステータスコードの使い分け
リダイレクトは、移動が恒久的か一時的か、メソッドを維持するかGETへ切り替えるかで使い分けるのが基本です。301と302だけでなく、303、307、308も役割を理解しておくと設計しやすくなります。
301は恒久移動、302は一時移動、303はPOST後にGETへ切り替えて別ページを見せたいときに使います。307は一時移動でメソッド維持、308は恒久移動でメソッド維持です。特にPOSTを扱う場合は、移動後のメソッドが変わるのか維持されるのかを意識する必要があります。
URL変更やSEOでは恒久/一時の違いが重要です。フォーム送信やログイン後遷移では、POSTの再送信を防ぐためにGETへ切り替える設計が重要です。目的に合わせてステータスコードを選ぶことで、意図しない再送信やURL評価のズレを防ぎやすくなります。
6-2. 実装前の確認チェックリスト
リダイレクトを実装する前に、移動の目的とHTTPメソッドの扱いを確認すると失敗を減らせます。以下の観点をチェックしましょう。
- 移動は恒久的か一時的か
- 移動先URLを
Locationヘッダーで正しく返しているか - POST後にGETへ切り替えたいのか、メソッドを維持したいのか
- フォーム送信後はPRGパターンを検討しているか
- 恒久的なURL変更に302を使い続けていないか
- 307/308でPOST本文が再送される可能性を理解しているか
- ログインページなどをリダイレクト対象外にしているか
- 外部URLへ自由に飛ばすオープンリダイレクトを防いでいるか
リダイレクトは簡単に見えますが、ステータスコードの意味を間違えると、SEO、フォーム再送信、ログイン後遷移、API呼び出しに影響します。まずは「恒久か一時か」「GETへ変えるかメソッド維持か」を軸に判断しましょう。
7. 参考リンク
- MDN: Redirections in HTTP
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Redirections - MDN: 301 Moved Permanently
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301 - MDN: 302 Found
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302 - MDN: 303 See Other
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303 - MDN: 307 Temporary Redirect
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307 - MDN: 308 Permanent Redirect
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308