HTTPリダイレクト

リダイレクト (HTTP)

[2] 3xx 応答で他の URL を指定し、利用者エージェントにその URL要求を送信することを求めること、あるいはそのような応答のことを、 リダイレクト (redirect) といいます。

C
利用者エージェント
S
起源サーバー
S2
起源サーバー
C -> S
要求
S -> C
3xx Location: URL
C -> S2
URL要求
S2 -> C
応答

仕様書

プロトコル

[305] HTTPリダイレクトは、次のプロトコル要素により構成されます。

[23] 状態符号は多数ありますが、 Fetch Standard によって自動的なリダイレクトが行われることとされているのはリダイレクト状態に分類される 301, 302, 303, 307, 308 の5種類だけです。

状態符号の選択

[33] 著者 (Webアプリケーション開発者) は、 リダイレクトで使うべき状態符号を次のように決定できます。

  1. [50] captive portal の場合
    1. 511 を使うべきです (HTTPリダイレクトではありません)。
  2. [34] 即座に遷移させずに、いったん何らかのメッセージを表示してから移動させたい場合
  3. [52] 複数の移動先の候補がある場合
    1. 300HTML によるリンクで表現できます (HTTPリダイレクトではありません)。
  4. [46] Webサイトの移転等で他の URL を見るべき場合
    1. [47] 同等の新しい URL がある場合
      1. [59] POST しようとしたならリダイレクト先でも POST させたい場合
        1. 308
      2. [60] そうでもない場合
        1. 301
    2. [48] そうでない場合 (トップページへの移動など)
      1. 302
  5. [51] 不完全な URL から完全な URL に移動させたい場合 (ディレクトリーの末尾に / がない場合など)
    1. 301
  6. [54] 短縮URLから正規の URL への展開の場合
    1. 301
  7. [57] POST しようとしたならリダイレクト先でも POST させたい場合
    1. 307
  8. [45] その他の場合、例えば:
    • POST の後次のページに移動させたい場合
    • ログインページの類に移動させたい場合
    • OAuth 認証フロー
    • ガラケーなど特定装置向けのページに移動させたい場合
    • 特定言語版の URL に移動させたい場合
    1. 302

[76] Semantic Web 信者でもなければ、 303 が必要な場合は滅多にありません。

意味

[14] リダイレクトは、対象資源のかわりに、別の URL にアクセスするべきであることを表しています。

[15] その実際の意味は様々です。

処理

[539] 新旧の要求応答は、互いに完全に独立したものです。 HTTP プロトコルとしては状態は保持していません。新旧要求を異なる HTTP接続を使って送信しても何ら問題ありませんし、 新旧要求の送信先のがそもそも異なっているかもしれません。

相対 URL

[538] Location: ヘッダーには相対URL を指定することもできます。この値は実効要求URL基底URL として解決されます。

Location: を参照。

リダイレクトと要求メソッド

[11] 301302 では、 POST だった場合リダイレクト先では GET に書き換えます >>56。それ以外の要求メソッドはそのまま保持します。

[12] 303 では、リダイレクト先では GET に書き換えます >>56

[13] 307308 では、 リダイレクト先でもリダイレクト前の要求メソッドをそのまま保持します。

[307] 要求メソッド安全でない場合、自動的なリダイレクトには注意する必要があります。 利用者安全でない要求リダイレクトしてほしくないかもしれません。 >>306

[308] Location: があれば、 未対応の 3xx 状態符号であっても、 自動的にリダイレクトして構いません >>306

[517] 起源鯖は、 PUT 要求に対して対象資源の状態を変更せず、 他の資源に適用したい場合は、 適切な 3xx 応答を送信しなければなりません。 その場合利用者エージェントリダイレクトに従うか選ぶことができます。 >>518

[22] 現状 Fetch Standard ではリダイレクト前後の要求メソッドの変化を規定していません。

[98] HTTPクライアントによってはリダイレクト後の要求メソッドWebブラウザーと違った挙動になることがあります。 初期 HTTP 仕様の迷走と関係しているのですが、 クライアントによって動作が違うのは困ったものです。 新しいクライアントWeb互換性のために Webブラウザー (Fetch Standard) と同じ動作を実装するべきです。 互換性の問題の実例: GAS

リダイレクトとヘッダー

[7] リダイレクト前後で指定するべきヘッダーの同一性や差異について特に規定はありません。

[8] RFC 7231ヘッダーの仕様書に対し、リダイレクト前後で保持するべきか明記することを検討するよう求めています >>6

リダイレクトループ

[535] は、リダイレクト先としてリダイレクトを返す URL を指定しても構いません。

[536] 利用者エージェントリダイレクトにより要求を改めて送信した結果がリダイレクトの場合も、 更にそのリダイレクトに従うことが期待されています。

[523] クライアントは、リダイレクトの循環を検出して対処するべきです >>518

[524] なぜ MUST でなく SHOULD なのか謎です。 無限リダイレクト無限ループするようなクライアントはどう考えてもバグっており、 有害でしかありません。
[525] RFC 2068 は最大5回までとしており、注意が必要 >>518 です。

素片識別子

[540] 素片識別子が適切で無い場面もあるとして、 201 を例に挙げています >>534 が、 なぜか禁止はされていません。また 201 以外にも不適切な場面が存在することを暗示していますが、 実際に何が該当するのかは不明です。

[537] 利用者エージェントは、3xx 応答Location:素片識別子が含まれていない場合、 要求対象生成するのに使ったURL素片識別子を継承するものとして処理しなければなりません >>534

[41] http://foo.example/bar#fragment1 を取り寄せる時に、次のようになったとします。

C: GET /bar HTTP/1.1
C: Host: foo.example
C: 
S: 302 Found HTTP/1.1
S: Location: http://foo.example/hoge
S: 

この時、 UA の望ましい動作は、 (WWWブラウザであれば) http://foo.example/hoge を要求し、その #fragment1 を表示することです。

[42] 同じ例で、次のような応答があったとしましょう。

S: 302 Found HTTP/1.1
S: Location: http://foo.example/hoge#fragment2
S: 

この時 WWW ブラウザは、 http://foo.example/hoge#fragment2 を表示し、 #fragment1 のことは忘れます。

[44] >>42 で、「アドレス・バー」のような UI 部分をどうするかという問題がありますね。 301 なら新しい (#fragment2 の) URI にしてしまえばいいですが、 307 の時はどうなんでしょう。元の #fragment1 にしておくのと、 #fragment* は削ってしまうのと2種類考えられますが。

[43] 但し実際には、この #fragment の扱いについては仕様・実装がぐちゃぐちゃです。 できることならば Location 欄で素片識別子を使わないといけないようなことにならないようによく考えておくべきでしょう。それでも使わざるを得なくなったときは仕方ないですし、 UA の挙動なんて飾りです、偉い人には分からなくて結構と開き直るのも場合によってはありでしょう。

仕様書の類の言及

[24] >>20,>>5 RFC2396 (URI) によると absoluteURIfragment を含みません。従って HTTP/1.1 と CGI で仕様が不整合な気がします。

実際のところ fragment つき URI を送っても多くの URI は解釈する気がしますが、仕様的には無理ということでいいですか?

[35] >>24 HTTP/1.1 Specification Errata http://world.std.com/~lawrence/http_errata.html#location-fragments http://purl.org/NET/http-errata#location-fragments に載ってました。 (こんなの知らなかった。) >>6 の通り、 HTTP でも URI の後に #fragment をつけることが出来ます

[36] とはいえ、知らない実装者も居るだろうな。。。要注意ですね。

[37] >>35 の文書から、該当部分の注記。

There are circumstances in which a fragment identifier in a Location URL would not be appropriate:

  • With a 201 Created response, because in this usage the Location header specifies the URL for the entire created resource.
  • With a 300 Multiple Choices, since the choice decision is intended to be made on resource characteristics and not fragment characteristics.
  • With 305 Use Proxy.

At present, the behavior in the case where there was a fragment with the original URI, e.g.: http://host1.example.com/resource1#fragment1 where /resource1 redirects to http://host2.example.com/resource2#fragment2 is 'fragment1' discarded? Do you find fragment2 and then find fragment1 within it? We don't have fragment combination rules.

Location URL 中での素片識別子が適切でない場面があります。

  • 201 Created (作成しますた) 応答。 Location 頭を使用して作成された資源全体を URL を指定するものだから。
  • 300 Multiple Choices (複数選択肢)。選択決定は資源の性質についてなされるもので素片の性質についてではないから。
  • 305 Use Proxy (串使って)。

現在、元の URI に素片がある場合、例えば http://host1.example.com/resource1#fragment1/resource1http://host2.example.com/resource2#fragment2 に redirect している時に「fragment1」は捨てられているのでしょうか? fragment2 を探してそれから fragment2 を探すのでしょうか? 我々は素片組み合わせ規則は持っていません。

[38] >>37 の後半の問題、実際のところどうなんだろう? どっちにしる!とも言いがたいよなあ。

[39] Common User Agent Problems: Handle the fragment identifier of a URI when the HTTP request is redirected. http://www.w3.org/TR/cuap#cp-fragment

この W3C NOTE は、 #fragment に対応していない UA があるけどちゃんとしる! と言うと共に、 >>37-38 問題について、 #fragment2 にしる! と言っています (小文字 must)。

[310] Web Applications 1.0 r6322 Make Facebook work. See http://blogs.msdn.com/b/ieinternals/archive/2011/05/17/url-fragments-and-redirects-anchor-hash-missing.aspx ( ( 版)) http://html5.org/tools/web-apps-tracker?from=6321&to=6322

[311] URL Fragments and Redirects - EricLaw's IEInternals - Site Home - MSDN Blogs ( ( 版)) http://blogs.msdn.com/b/ieinternals/archive/2011/05/17/url-fragments-and-redirects-anchor-hash-missing.aspx

[312] draft-bos-http-redirect-00 - Handling of fragment identifiers in redirected URLs ( 版) http://tools.ietf.org/html/draft-bos-http-redirect-00

[10] RFC 7231 は、リダイレクトによって元の URL に指定されていた素片識別子をリダイレクト先の URL文書が読み取れることによる情報漏洩の危険があることを指摘しています >>9

実装について

[58] WinIE 6.0 (もしかしたら以前の版も。) は redirect された時の Location URI 参照に素片識別子がついていると直後の再要求時にその素片識別子ごと Request-URI にして送ってしまうみたいです。 (名無しさん 2004-05-03 04:37:14 +00:00)

HTTP 以外の URL

...

リダイレクトの開始

[543] HTTPリダイレクトは、応答の直後にリダイレクト後の要求が送信されることを期待しています。

[544] 仕様上は応答から要求までの待ち時間を Retry-After: ヘッダーで指定できることになっていますが、実装されていませんし、 今後実装される見込みもなさそうです。

[545] 一旦何らかのページを表示して、すこし待ってから別のページを表示したいときは、 Refresh を利用できます。

[309] WinIE8OperaChromeFirefox のどの Webブラウザーも、 リダイレクトしている HTTPメッセージ全体が到着するのを待たず、 頭部を受け取り次第すぐにリダイレクト先の URL の取得をはじめるようです。

http://suika.fam.cx/~wakaba/-temp/test/http/redirect/delayed.cgi (頭部はすぐに返すものの、応答本体の生成が終わるまで100秒かかる例)。
Location: 頭欄を受け取り次第すぐに次に進むのか、 頭部をすべて受け取り終わるまで進まないのかは未検証です。

セキュリティー

参照元

[68] Set request’s referrer policy on redirect は、 要求応答について次のようにします >>67

  1. [69] 方針を、応答Parse a referrer policy from a Referrer-Policy header を適用した結果に設定します。
  2. [70] 方針空文字列でなければ、
    1. [71] 要求参照元ポリシーを、方針に設定します。

[74] これは HTTPリダイレクトfetch から呼び出されます。

利用者インターフェイス

[78] アドレスバーも参照。

実装

[100] まきのっぴさんはTwitterを使っています: 「そこで「それリダイレクト設定どこに書きました? .htaccessに書いてない? でしょ? じゃあhttpd.confに書いて再検証してみて」と指示してやり直した結果、許容し得る性能低下で済むようになったとの報告があり、数万行のリダイレクト設定を施したリニューアルが無事実現できました。」 / Twitter, , https://twitter.com/pmakino/status/1642930069403484160

[99] tecklさんはTwitterを使っています: 「ちなみにNginxでリダイレクトさせた時は、起動時にメモリを食うものの速度自体は普通に高速でした。 その後リダイレクト件数が200万件?を超えてきてメモリも厳しくなったので Nginx + Go + SQLiteの動的リダイレクトに切り替えたら超省メモリになりました(便乗宣伝) https://t.co/PCPSVmJNBo」 / Twitter, , https://twitter.com/teckl/status/1643101178165878784

歴史

[519] リダイレクトには、元々の要求要求対象を書き換え、 要求メソッドを維持するパターンと、要求メソッドGET に書き換えるパターンがあります。

[520] HTTP 仕様書の著者の意図は、 301302 は前者とするものでしたが (CERN の実装もそうなっていました)、 実際には 303 共々後者の動作とする実装があり、 やがて後者に収束していきました。 >>306

[521] このため後者の意味の 307 が新たに追加されました。 更に、要求メソッドPOST だった場合のみ、 301302 で前者の動作でも適合することとされました。 >>306

[522] HTTP の仕様書の著者の意図としては、依然として 301302 は元の要求メソッドのままリダイレクトするのが正しい使い方のようです。 15年以上にわたり安定している現在の慣習と互換性のない“理論上は正しい” 方式にこだわり続ける意図が何なのかは謎です。 Webブラウザー側の Webアプリケーションも、 301302要求メソッドが保持されることなど想定しておらず、 そうでない実装方法は決してWeb互換では無いのですが・・・。

[1] リダイレクトの設定とインデックスに登録されるURL - インフォセンター - Yahoo!検索 ( 版) http://info.search.yahoo.co.jp/archives/002865.php

関連

[3] 通常は HTTPリダイレクトとは呼びませんが、 Refresh: ヘッダー (や <meta http-equiv=refresh>)、 HSTSリダイレクトを実現するものです。

[4] またリダイレクトには JavaScript によってクライアント側で実行する手法もあります。

[5] HTTP の仕様書は、 300304リダイレクトと呼んでいます。

3xx の項を参照。

[542] 201 でも Location: を使いますが、本項のHTTPリダイレクトとは異なります。

[541] HTTP には他に Content-Location:Link: もありますが、本項の HTTPリダイレクトとは異なります。

[526] CGI には局所リダイレクト応答クライアントリダイレクト応答がありますが、 クライアントリダイレクト応答HTTP応答におけるリダイレクトに相当します。

[27] Referrer によってリンク元が送信されてしまうことを防ぐため、 本来のリンク先との中間に1ステップ挟む“中間ページ”型リンクも、 広義のリダイレクトと言えます。 Refreshlocation.href と併用することで中間ページを設けつつ自動でリンク先に遷移させる本当のリダイレクトになっている場合もあります。

[28] ガラケーのようなリダイレクト回数の制限の厳しい利用者エージェントとの互換性のため、 敢えてHTTPリダイレクトを使わずに >>27 のような中間ページを使うこともあります。

メモ

[527] Response.redirect() > new RedirectResponse() · a083a27 · whatwg/fetch ( ( 版)) https://github.com/whatwg/fetch/commit/a083a27c53a65e5ba93c486401fb55c2a68a7cd3

[528] HTTP - WHATWG Wiki ( ( 版)) http://wiki.whatwg.org/wiki/HTTP#Redirects

[529] HTTP Methods and Redirect Status Codes - IEInternals - Site Home - MSDN Blogs ( ( 版)) http://blogs.msdn.com/b/ieinternals/archive/2011/08/19/understanding-the-impact-of-redirect-response-status-codes-on-http-methods-like-head-get-post-and-delete.aspx

[530] 598304 – XHR rewrites non-POST methods upon 301/302 redirects ( ( 版)) https://bugzilla.mozilla.org/show_bug.cgi?id=598304

[531] 676059 – Make redirect prompting depend on HTTP-safeness of method, not presence of request body ( ( 版)) https://bugzilla.mozilla.org/show_bug.cgi?id=676059

[532] Test Cases for HTTP Redirects ( ( 版)) http://greenbytes.de/tech/tc/httpredirects/

[533] Bug 60440 – [Qt] Redirection of HTTP POST (3xx) incorrectly includes original POST data ( ( 版)) https://bugs.webkit.org/show_bug.cgi?id=60440

[330] auガラケーだと素片識別子が入っていると 404 になります。

[406] Location: javascript:alert(1) が返ってきた時のブラウザの動作 - Qiita [キータ] ( ( 版)) http://qiita.com/ooooooo_q/items/1f0c2c64413495c46e6b

[410] HTTP - WHATWG Wiki ( ( 版)) http://wiki.whatwg.org/wiki/HTTP#Location_header

[423] URL Fragments and Redirects - IEInternals - Site Home - MSDN Blogs ( ( 版)) http://blogs.msdn.com/b/ieinternals/archive/2011/05/17/url-fragments-and-redirects-anchor-hash-missing.aspx

[29] Refactor manual redirect flag into redirect mode. Preparation for https:... · whatwg/fetch@8398149 ( 版) https://github.com/whatwg/fetch/commit/83981498175633510878ebf97077ec632ceedc29

[30] Provide limited control over redirects. Fixes https://www.w3.org/Bugs/Pu... · whatwg/fetch@b6b4f87 ( 版) https://github.com/whatwg/fetch/commit/b6b4f87048020cda6237ca4af02df62d43f99765

[31] 598304 – XHR rewrites non-POST methods upon 301/302 redirects ( 版) https://bugzilla.mozilla.org/show_bug.cgi?id=598304

[32] Certain redirects rewrite the request method. Fixes #32 · whatwg/fetch@a8e07c8 ( 版) https://github.com/whatwg/fetch/commit/a8e07c886198e85ca3eb757f3ef284193da11a0f

[61] Put redirect statuses in a shorthand. · whatwg/fetch@bd284d1 ( 版) https://github.com/whatwg/fetch/commit/bd284d112e207c900c61d90c8bd005a4b6e1d687

[63] POSTリクエストをリダイレクトするとGETされる?POSTされる? - はこべブログ ♨ ( 版) http://hakobe932.hatenablog.com/entry/20090707/1246985195

[64] Fix #187: set body to null when method is set to `GET` in a redirect · whatwg/fetch@379daf2 ( 版) https://github.com/whatwg/fetch/commit/379daf2b451b026f5fe2012da2f6e01ceccb3b58

[65] Revert #111: allow redirects to data URLs · whatwg/fetch@31f65e4 ( 版) https://github.com/whatwg/fetch/commit/31f65e4625eacb3a74b5d1eba905d0600040c6ce

[66] Allow user agents to transmit RST_STREAM upon seeing a redirect · whatwg/fetch@af0dc92 ( 版) https://github.com/whatwg/fetch/commit/af0dc923f7636751996a9762309904511725a1a7

[72] Non-HTTP(S) schemes are a network error during redirects ( (annevk著, )) https://github.com/whatwg/fetch/commit/9b75908a1e6f6f520a77b8b420015a61fb5d8512

[73] Navigate: remove "gone async" and define redirect handling (annevk著, ) https://github.com/whatwg/html/commit/8b630f5e4fa2ec8b0999470d09490bffe6e9a1e3

[75] Call out to Referrer Policy to set policy on redirect (estark37著, ) https://github.com/whatwg/fetch/commit/a8f1cd5ae2d080ee4e1e8e02b68e8ec6ae2c2833

[77] Release Notes for Safari Technology Preview 17 | WebKit ( ()) https://webkit.org/blog/7071/release-notes-for-safari-technology-preview-17/

Ensured the redirection count is no more than 20 in case of cross origin requests (r208046)

Ensured redirections are upgraded only if declared by CSP policy (r207752)

[79] Webmention () https://webmention.net/draft/#h-limits-on-get-requests

Receivers should place limits on the number of HTTP redirects they follow, for example limiting the number to 20, in order to prevent being stuck in a redirect loop if the sender continues to send redirects.

[80] Do not always set the recursive flag in HTTP-redirect fetch (annevk著, ) https://github.com/whatwg/fetch/commit/869ec2c2224200988bbc604f7f5181b6bb9df2c3

[81] RFC 5323 - Web Distributed Authoring and Versioning (WebDAV) SEARCH () https://tools.ietf.org/html/rfc5323#section-5.4

[82] More eargerly send RST_STREAM on redirects (annevk著, ) https://github.com/whatwg/fetch/commit/fd286755e9664d570260c16f7c1933f424d2f39a

[83] Clarify semantics of checking done, closed, etc. states of a null body stream · Issue #635 · whatwg/fetch () https://github.com/whatwg/fetch/issues/635

[84] More eargerly send RST_STREAM on redirects by annevk · Pull Request #638 · whatwg/fetch () https://github.com/whatwg/fetch/pull/638

[85] ads.txt で認定販売者を宣言する - DoubleClick for Publishers ヘルプ () https://support.google.com/dfp_premium/answer/7441288?hl=ja

ads.txt v1.0.1 への仕様更新に伴い、Google では元のルートドメイン外への単一の HTTP リダイレクトがサポートされるようになります(例: example1.com/ads.txt から example2.com/ads.txt へのリダイレクト)。

元のルートドメイン内であれば、複数のリダイレクトもサポートされます。

[86] Response.redirect() results in status message still being OK? · Issue #664 · whatwg/fetch () https://github.com/whatwg/fetch/issues/664

[87] "no-cors" POST and 307/308 redirects · Issue #593 · whatwg/fetch () https://github.com/whatwg/fetch/issues/593

[88] Avoid using the CORS flag to reset request's origin in redirects by annevk · Pull Request #594 · whatwg/fetch () https://github.com/whatwg/fetch/pull/594

[89] Preserve HEAD method on 303 redirect (annevk著, ) https://github.com/whatwg/fetch/commit/6f29b764cc57aaf2f431e15a3f0fec029926e9e0

[90] 303 redirects should preserve HEAD · Issue #753 · whatwg/fetch () https://github.com/whatwg/fetch/issues/753

[91] Preserve HEAD method on 303 redirect by annevk · Pull Request #796 · whatwg/fetch () https://github.com/whatwg/fetch/pull/796

[92] Added a note about fetch redirects being covered by andypaicu · Pull Request #359 · w3c/webappsec-csp () https://github.com/w3c/webappsec-csp/pull/359

[93] Note somewhere that redirects are covered by fetch directives. · Issue #72 · w3c/webappsec-csp () https://github.com/w3c/webappsec-csp/issues/72

[94] Take tainted origin flag into account for the same origin check (annevk著, ) https://github.com/whatwg/fetch/commit/986618a62b2d7d31f93177ed178f0cb21b570d85

[95] fetch() "no-cors": cross-origin to same-origin redirect taints response · Issue #737 · whatwg/fetch () https://github.com/whatwg/fetch/issues/737

[96] Request's tainted origin flag fallout · Issue #756 · whatwg/fetch () https://github.com/whatwg/fetch/issues/756

[97] Take tainted origin flag into account for the same origin check by annevk · Pull Request #834 · whatwg/fetch () https://github.com/whatwg/fetch/pull/834

[101] RFC 4437: Web Distributed Authoring and Versioning (WebDAV) Redirect Reference Resources, , https://www.rfc-editor.org/rfc/rfc4437.html