HTTP のリダイレクト
URL リダイレクトは、 URL 転送とも呼ばれ、ページ、フォーム、ウェブサイト全体、ウェブアプリケーションなどに 2 つ以上の URL のアドレスを与える技術です。 HTTP ではこの操作のために、特別な種類のレスポンスである HTTP リダイレクトを提供しています。
リダイレクトには多くの目的があります。
- サイトをメンテナンスしている間の一時的なリダイレクト
- サイトの構成を変更した後も外部のリンクを機能させるための恒久的なリダイレクト、ファイルをアップロードしているときの進捗を示すページなど
原理
恒久的リダイレクト
これらのリダイレクトは永遠に続くことを意味します。これらのリダイレクトは、元の URL はもう使用されず、新しいものに置き換えるべきであることを示しています。検索エンジンのロボット、 RSS リーダー、および他のクローラーは、リソースの元の URL を更新します。
コード | テキスト | メソッドの扱い | 主な使用例 |
---|---|---|---|
301 |
Moved Permanently |
GET メソッドは変更しません。 他のメソッドは GET に変更されるかもしれません。[1] |
ウェブサイトの再編。 |
308 |
Permanent Redirect |
メソッドや本文は変更しません。 | GET 以外のリンクや操作を含むウェブサイトの再編。 |
[1] 仕様書ではメソッドの変更を意図していませんが、メソッドを変更するユーザーエージェントが存在します。 308
が定義されたのは、 GET
以外のメソッドを使用するときの動作のあいまいさをなくすためです。
一時的リダイレクト
正規の場所でレスポンスしたリソースにアクセスすることはできませんが、別の場所でアクセスできる場合があります。このような場合に、一時的なリダイレクトを使用できます。
検索エンジンのロボットは、新たな一時的 URL を記録しません。一時的リダイレクトは、リソースを作成、更新、削除しているときに一時的な進捗ページを提供するためにも利用されます。
コード | テキスト | メソッドの扱い | 主な使用例 |
---|---|---|---|
302 |
Found |
GET メソッドは変更しません。 他のメソッドは GET に変更されるかもしれません。[2] |
ウェブページは不測の理由により、一時的に利用できない状態です。 |
303 |
See Other |
GET メソッドは変更しません。 他のメソッドは GET に変更します (本文は失われます)。 |
ページの再読み込みによって操作が再度実施されることを防ぐために、PUT や POST の後のリダイレクトで使用します。 |
307 |
Temporary Redirect |
メソッドと本文は変更しません。 | ウェブページは不測の理由により、一時的に使用できない状態です。検索エンジンは自身のリンクを更新しません。 302 と比較して、サイトで GET 以外の操作を使用できる場合に推奨されます。 |
[2] 仕様書ではメソッドの変更を意図していませんが、実際はメソッドを変更するユーザーエージェントが存在します。GET
以外のメソッドを使用するときの動作のあいまいさをなくすために、 307
が定義されました。
特殊リダイレクト
304
(Not Modified) は、ページをローカルにキャッシュした(陳腐化した)複製へリダイレクトします。また 300
(Multiple Choice) は、手動リダイレクトです。ブラウザーがウェブページとして表示する本文には使用可能なリダイレクトのリストがあり、ユーザーはひとつ選択してクリックします。
コード | テキスト | 主な使用例 |
---|---|---|
300 |
Multiple Choice |
多くはありません。本文内の HTML ページに選択肢の一覧があります。 Link ヘッダーに rel=alternate がある場合は、機械可読な選択肢を提供することが推奨されます。 |
304 |
Not Modified |
再検証された条件付きリクエストのために送信されます。キャッシュされたレスポンスがまだ新鮮で使用可能であることを示します。 |
リダイレクトを指定する代替手段
HTML リダイレクト
HTTP リダイレクトはリダイレクトを作成するための最良の方法ですが、サーバーの制御権を持っていない場合もあります。このような場合は、そのページの <head>
内に <meta>
要素を記述し、その http-equiv
属性に Refresh
を設定してみてください。ページを表示すると、ブラウザーは示されたページへ移動します。
<head>
<meta http-equiv="Refresh" content="0; URL=https://example.com/" />
</head>
content
属性は、指定した URL へリダイレクトする前にブラウザーが何秒待つべきかを示す値から始まります。アクセシビリティを高めるため、常に 0
を設定しましょう。
当然ながらこの方法は HTML でしか動作せず、画像などのコンテンツでは使用できません。
JavaScript リダイレクト
JavaScript のリダイレクトは window.location
プロパティに URL 文字列を設定することで実行され、新たなページが読み込まれます。
window.location = "https://example.com/";
HTML リダイレクトと同様にすべてのリソースでは動作できず、また JavaScript を実行するクライアントでしか動作しないことは明らかです。一方、例えば特定の条件に一致した場合にのみリダイレクトを行うなど、さまざまな可能性があります。
優先順位
リダイレクトを起動する方法が 3 種類あり、同時に複数の方法を指定できますが、どのリダイレクトが最初に適用されるのでしょうか?
- HTTP リダイレクトが常に最初に動作します。 — 転送されるページがない場合でも存在するからです。
- HTTP リダイレクトが存在しなければ、HTML リダイレクト (
<meta>
) が動作します。 - JavaScript リダイレクトが最後に、 JavaScript が有効であれば実行されます。
可能であれば常に HTTP リダイレクトを使用して、<meta>
は追加しないようにしましょう。誰かが HTTP リダイレクトを変更して HTML リダイレクトを変更し忘れると、リダイレクトが同一ではなくなったり、無限ループになったり、その他の問題が発生したりします。
使用例
リダイレクトの使用例は多数ありますが、どのリダイレクトもパフォーマンスへの影響がありますので、使用は最小限にとどめるべきです。
ドメインの別名
理想的なのは、ひとつのリソースに対してひとつの場所、そしてひとつの URL が存在することです。しかし、リソースに別名を設定する理由はいくつかあります。
- サイトへの到達方法を拡大するため
-
よくある事例は、サイトが
www.example.com
ドメイン配下に存在しているとき、example.com
からもアクセスできるようにしたい場合です。この場合は、example.com
からwww.example.com
へのリダイレクトを設定します。また、一般的に使用される同義語や、ドメイン名の打ち間違いで頻度が多いものを提供してもよいでしょう。 - 別のドメインに移動するため
-
例えば、会社名が変わっても、既存のリンクやブックマークからも新しい会社名を見つけられるようにしたいでしょう。
- HTTPS を強制するため
-
http://
版のサイトへのリクエストをhttps://
版のサイトにリダイレクトします。
リンクの存続
ウェブサイトを再構築すると URL が変わります。サイトのリンクを新しい URL に合うよう更新しても、外部リソースからのリンクで使用されている URL を制御することはできません。
外部のリンクは貴重なユーザーを連れてきてくれるし、 SEO にも役立つため、リンクを壊したくはありません。よって、古い URL から新しい URL へのリダイレクトを設定します。
メモ: この手法は内部のリンクにも有効ですが、内部のリダイレクトは避けるようにしてください。リダイレクトは(追加の HTTP リクエストを行うため)性能の負担がかなりあります。内部のリンクを修正することでこれを避けられるのであれば、リンクを修正してください。
安全でないリクエストへの一時的なレスポンス
長いリクエストに対する一時的なレスポンス
一般的なサーバーにおけるリダイレクトの設定
Apache
リダイレクトはサーバーの設定ファイルか、各ディレクトリの .htaccess
で設定できます。
mod_alias
モジュールには Redirect
および RedirectMatch
ディレクティブがあり、これらは既定で 302
レスポンスを設定します。
<VirtualHost *:443>
ServerName example.com
Redirect / https://www.example.com
</VirtualHost>
URL https://example.com/
は https://www.example.com/
にリダイレクトされ、その下のファイルやディレクトリも同様です (https://example.com/some-page
は https://www.example.com/some-page
にリダイレクトされます)。
RedirectMatch
も同じですが、対象の URL の集合を定義するために正規表現を使用します。
RedirectMatch ^/images/(.*)$ https://images.example.com/$1
images/
フォルダー内のすべての文書が、別のドメインにリダイレクトされます。
一時的なリダイレクトを設定したくない場合は、別の種類のリダイレクトを設定するために追加引数 (使用する HTTP ステータスコードまたは permanent
キーワード) を使用できます。
Redirect permanent / https://www.example.com # …acts the same as: Redirect 301 / https://www.example.com
mod_rewrite
モジュールでリダイレクトを作成することもできます。こちらはさらに柔軟性がありますが、若干複雑です。
Nginx
Nginx では、リダイレクトしたいコンテンツ用の server ブロックを作成します。
server { listen 80; server_name example.com; return 301 $scheme://www.example.com$request_uri; }
ディレクトリまたは特定のページにのみリダイレクトを適用するには、rewrite
ディレクティブを使用します。
rewrite ^/images/(.*)$ https://images.example.com/$1 redirect; rewrite ^/images/(.*)$ https://images.example.com/$1 permanent;
IIS
IIS では、<httpRedirect>
要素を使用してリダイレクトを設定します。
リダイレクトループ
追加のリダイレクトが、すでに通っている経路をたどるとリダイレクトループが発生します。言い換えると終わらないループが存在しており、最終的に見つかるページはありません。
ほとんどの場合はサーバーの問題であり、サーバーで検出できる場合は 500
Internal Server Error
を返すでしょう。サーバーの設定を変更した直後にこのようなエラーが発生した場合は、リダイレクトループが発生しているかもしれません。
時々、サーバーがリダイレクトループを検出しないことがあります。それぞれのサーバーでは全貌を把握できない、複数のサーバーにわたるリダイレクトループがあり得ます。この場合はブラウザーがループを検出して、エラーメッセージを表示するでしょう。Firefox では以下のメッセージを表示します。
Firefox は、サーバーがこのアドレスへのリクエストを決して終了しない方法でリダイレクトしていることを検出しました。
Chrome では以下のように表示されます。
このウェブページにはリダイレクト ループが含まれています
どちらの場合も、ユーザーができることはほとんどありません (キャッシュや Cookie の不一致など、ユーザー側で問題が発生している場合を除きます)。
リダイレクトループは使い勝手をを完全に損ないますので、避けることが重要です。