MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

HTTP のリダイレクション

URL リダイレクションまたは URL 転送は、ページ、フォーム、ウェブアプリケーション全体といった実際のリソースが異なる URL に存在していてもリンクを存続させる技術です。サイトをメンテナンスしている間の一時的なリダイレクト、サイトの構成を変更した後も外部のリンクを機能させるための恒久的なリダイレクト、ファイルをアップロードしているときの進捗を示すページなど、さまざまな目的で使用されるこの操作を実行するために、HTTP は特別なレスポンスである HTTP リダイレクトを提供しています。

原理

HTTP では、リクエストに対してリダイレクトという特別なレスポンスを送信することによって、サーバーがリダイレクションを発生させます。HTTP リダイレクトは、3xx のステータスコードを持つレスポンスです。ブラウザーはリダイレクトレスポンスを受け取ると、提供された新たな URL を使用して直ちに読み込みを行います。ほとんどの場合、リダイレクションはわずかなパフォーマンスへの影響を除けばユーザーに対して透過的です。

数種類のリダイレクトがあり、それらは一時的リダイレクション、恒久的リダイレクション、特殊リダイレクションの 3 つのカテゴリーに分類されます。

恒久的リダイレクション

これらのリダイレクションは、永久に続くことを意味します。元の URL は今後使用されず、新しい URL を使用すべきであることを示唆します。検索エンジンのロボットは検索インデックスで、リソースに関連付けられた URL を更新します。

コード テキスト メソッドの扱い 主な使用例
301 Moved Permanently GET メソッドは変更しません。
他のメソッドは GET に変更されるかもしれません。[1]
ウェブサイトの再編。
308 Permanent Redirect メソッドやボディは変更しません。 GET 以外のリンクや操作を含むウェブサイトの再編。

[1] 仕様ではメソッドの変更を意図していませんが、実際はメソッドを変更するユーザーエージェントが存在します。GET 以外のメソッドを使用するときの動作のあいまいさをなくすために、308 が定義されました。

一時的リダイレクション

正規の場所で要求したリソースにアクセスすることはできませんが、別の場所でアクセスできる場合があります。このような場合に、一時的なリダイレクトを使用できます。検索エンジンのロボットは、新たな一時的リンクを記録しません。一時的リダイレクションは、リソースを作成、更新、削除しているときに一時的な進捗ページを提供するためにも利用されます。

コード テキスト メソッドの扱い 主な使用例
302 Found GET メソッドは変更しません。
他のメソッドは GET に変更されるかもしれません。[2]
ウェブページは既知の理由により、一時的に使用できません。検索エンジンは自身のリンクを更新しません。
303 See Other GET メソッドは変更しません。
他のメソッドは GET変更します (ボディは失われます)。
ページの再読み込みによって操作が再度実施されることを防ぐために、PUTPOST の後のリダイレクトで使用します。
307 Temporary Redirect メソッドやボディは変更しません。 ウェブページは既知の理由により、一時的に使用できません。検索エンジンは自身のリンクを更新しません。サイトで GET 以外のリンクや操作を使用できる場合は、302 より推奨されます。

[1] 仕様ではメソッドの変更を意図していませんが、実際はメソッドを変更するユーザーエージェントが存在します。GET 以外のメソッドを使用するときの動作のあいまいさをなくすために、307 が定義されました。

特殊リダイレクション

前出の一般的なリダイレクションに加えて、特殊なリダイレクションが 2 つあります。304 (Not Modified) は、ページをローカルにキャッシュした (陳腐化した) 複製へリダイレクトします。また 300 (Multiple Choice) は、手動リダイレクションです。ブラウザーがウェブページとして表示するボディには使用可能なリダイレクションのリストがあり、ユーザーはひとつ選択してクリックします。

コード テキスト 主な使用例
300 Multiple Choice 多くはありません。ボディ内の HTML ページに選択肢の一覧があります。200 OK ステータスで提供されるかもしれません。
304 Not Modified キャッシュのリフレッシュ。キャッシュの値はまだ新鮮であり、使用できることを示します。

リダイレクションを指定する代替手段

HTTP リダイレクトは、リダイレクションを定義する唯一の手段ではありません。このほかに <meta> 要素を使用する HTML リダイレクションと、DOM を使用する JavaScript リダイレクションという 2 つの方法があります。

HTML リダイレクション

HTTP リダイレクトはリダイレクションを作成するために好ましい方法ではありませんが、ウェブ開発者がサーバーを制御できない、あるいは設定できない場合があります。このようなケースでは、ウェブ開発者は <head> 内に <meta> 要素と refresh を設定した http-equiv 属性を持つ HTML ページを構築できます。ページを表示するとブラウザーはこの要素を発見して、示されたページへ移動します。

<head> 
  <meta http-equiv="refresh" content="0;URL='http://www.example.com/'" />
</head>

content 属性は、指定した URL へリダイレクトする前にブラウザーが何秒待つべきかを示す値から始まります。アクセシビリティを高めるため、常に 0 を設定しましょう。

当然ながらこの方法は HTML ページ (あるいは同様のリソース) でしか動作せず、画像などのコンテンツでは使用できません。

このリダイレクションはブラウザーの戻るボタンの動作を乱しますので注意してください。このヘッダーを持つページに戻ることはできますが、即座に再び転送されます。

JavaScript リダイレクション

JavaScript のリダイレクションは window.location に値を設定することで作成され、新たなページが読み込まれます。

window.location = "http://www.example.com/";

HTML リダイレクションと同様にすべてのリソースでは動作できず、また JavaScript を実行するクライアントでしか動作しないことは明らかです。一方、例えば特定の条件に一致した場合にのみリダイレクションを行うなど、さまざまな可能性があります。

優先順位

使用可能な URL リダイレクションが 3 種類あり、同時に複数の方法を指定できますが、どのリダイレクションが始めに適用されるのでしょうか? 優先順位は以下のとおりです:

  1. ページが転送されていない、および読み込まれていない状態でも、HTTP リダイレクションが常に最初に動作します。
  2. HTTP リダイレクトが存在しなければ、HTML リダイレクト (<meta>) が動作します。
  3. JavaScript リダイレクトが最後に使用されます。また、クライアント側で JavaScript が有効である場合に限り動作します。

可能であれば常に HTTP リダイレクトを使用して、<meta> は使わないようにしましょう。開発者が HTTP リダイレクトを変更して HTML リダイレクトの変更を忘れると、リダイレクトが同一ではなくなる、無限ループになる、あるいは他の問題が発生します。

使用例

リダイレクトの使用例は多数ありますが、どのリダイレクトもパフォーマンスへの影響がありますので、使用は最小限にとどめるべきです。

ドメインの別名

理想的には、ひとつのリソースに対してひとつの場所、そしてひとつの URL が存在します。しかし、リソースに対して別名を持ちたい理由ががあります (複数のドメイン、www 接頭辞がある URL とない URL、覚えやすくて短い URL など)。このような場合はリソースを重複させず、ひとつの正しい (正式な) URL へのリダイレクトを使用すると便利です。

ドメインの別名は、いくつかの理由で実施できます:

  • サイトへの到達方法を広げます。よくある事例は、サイトが www.example.com ドメイン配下に存在しているとき、example.com からページにアクセスすることも可能にしたい場合です。この場合は、example.com のページから www.example.com へのリダイレクションを設定します。また、一般的に使用される同義語や、ドメイン名のタイプミスで頻度が多いものを提供してもよいでしょう。
  • 別のドメインに移動します。例えば会社名が変わった後に古い社名で検索するとき、以前の会社のウェブサイトを使用する人々が新しい社名のもとで今までどおり見つけられるようにしたいでしょう。
  • HTTPS を強制します。HTTP 版のサイトへのリクエストを HTTPS 版のサイトにリダイレクトします。

ウェブサイトを再構築すると、リソースの URL が変わります。ウェブサイトの内部のリンクは新しい命名体系に合わせるよう更新できますが、外部のリソースで使用している URL は制御できません。外部のリンクは貴重なユーザーを連れてきますので (および SEO のため)、リンクを壊したくはありません。よって、古い URL から新しい URL へのリダイレクトを設定します。

この手段は内部のリンクを機能させることもできますが、内部のリダイレクトは避けるようにするべきです。リダイレクトはパフォーマンスの負担がかなりあります (追加の HTTP リクエストを行うため)。内部のリンクを正しくすることでこれを避けられるのであれば、リンクを修正するべきです。

安全でないリクエストへの一時的なレスポンス

安全でない リクエストはサーバーの状態を変更するものであり、ユーザーがうっかり再実行するべきではありません。一般的に、ユーザーが PUTPOSTDELETE のリクエストを再送信することは望みません。リクエストの結果としてレスポンスを返すだけである場合は、単に再読み込みボタンを押すことで (おそらく確認メッセージの後に)、リクエストを再送信します。

この場合、サーバーは正しい情報を持つ 303 (See Other) レスポンスを返すことができます。一方、再読み込みボタンが押された場合はページを再表示するだけであり、安全でないリクエストを再実行しません。

長いリクエストに対する一時的なレスポンス

時には DELETE リクエストを後で処理するように予定するなど、一部のリクエストはサーバー側で長い時間が必要になる場合があります。この場合はアクションが予定に追加されたことを示して、最終的に進捗の表示やキャンセルを可能にするページへリンクするリダイレクトの 303 (See Other) をレスポンスにします。

一般的なサーバーにおけるリダイレクトの設定

Apache

リダイレクトはサーバーの設定ファイルか、各ディレクトリーの .htaccess で設定できます。

mod_alias モジュールに、302 レスポンスを設定するための Redirect および Redirect_Match ディレクティブがあります (デフォルト):

<VirtualHost *:80>
	ServerName example.com
	Redirect / http://www.example.com
</VirtualHost>

URL http://example.com/http://www.example.com/ にリダイレクトします (http://example.com/other.html ではありません)。

Redirect_Match も同じですが、対象の URL の集合を定義するために正規表現を使用します:

RedirectMatch ^/images/(.*)$ http://images.example.com/$1

images/ フォルダー内のすべてのドキュメントが、別のドメインにリダイレクトされます。

一時的なリダイレクトを設定したくない場合は、別の種類のリダイレクトを設定するために追加パラメーター (使用する HTTP ステータスコードまたは permanent キーワード) を使用できます:

Redirect permanent / http://www.example.com
Redirect 301 / http://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/(.*)$ http://images.example.com/$1 redirect;
rewrite ^/images/(.*)$ http://images.example.com/$1 permanent;

IIS

IIS では、<httpRedirect> 要素を使用してリダイレクションを設定します。

リダイレクションループ

連続的なリダイレクションが、すでに通っている経路をたどるとリダイレクションループが発生します。言い換えると終わらないループが存在しており、最終的に見つかるページはありません。

ほとんどの場合はサーバーの問題であり、サーバーが検出できない場合は 500 Internal Server Error を返すでしょう。サーバーの設定を変更した直後にこのようなエラーが発生した場合は、リダイレクションループが発生しているかもしれません。

時々、サーバーがリダイレクションループを検出しないことがあります。それぞれのサーバーでは全貌を把握できない、複数のサーバーにわたるリダイレクションループがあり得ます。。この場合はブラウザーがループを検出して、エラーメッセージを表示するでしょう。Firefox では以下のメッセージを表示します:

このアドレスへのリクエストに対するサーバの自動転送設定がループしています。

Chrome では以下のように表示します:

このウェブページにはリダイレクト ループが含まれています

どちらの場合も、ユーザーができることはほとんどありません (キャッシュや Cookie の不一致など、ユーザー側で問題が発生している場合を除きます)。

リダイレクションループはユーザー体験を完全に損ないますので、避けることが重要です。

ドキュメントのタグと貢献者

タグ: 
 このページの貢献者: yyss
 最終更新者: yyss,