/
64.txt
369 lines (270 loc) · 20.7 KB
/
64.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
[2] [CODE(HTTP)[[[3xx]]]] [[応答]]で他の [[URL]] を指定し、[[利用者エージェント]]にその
[[URL]] に[[要求]]を送信することを求めること、あるいはそのような[[応答]]のことを、
[DFN[[RUBYB[[[リダイレクト]]]@en[redirect]]]]といいます。
[FIG(sequence)[
:C:[[利用者エージェント]]
:S:[[起源鯖]]
:S2:[[起源鯖]]'
:C -> S:[[要求]]
:S -> C:[CODE(HTTP)[[[3xx]]]] [CODE(HTTP)@en[[[Location:]] [VAR[URL]]]]
:C -> S2:新 [VAR[URL]] に[[要求]]
:S2 -> C:[[応答]]
]FIG]
* 仕様書
[REFS[
- [306] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-6.4>
- [518] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-06-07 01:55:45 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-4.3.4>
- [534] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-7.1.2>
- [6] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#page-79>
- [9] [CITE@en[RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content]] ([TIME[2014-08-07 05:54:02 +09:00]] 版) <https://tools.ietf.org/html/rfc7231#section-9.5>
]REFS]
* 構成要素
[305] [[HTTPリダイレクト]]は、次の[[プロトコル要素]]により構成されます。
[FIG(short list)[
- [[状態符号]] [CODE(HTTP)[[[3xx]]]]
-- [CODE(HTTP)[[[300]]]]
-- [CODE(HTTP)[[[301]]]]
-- [CODE(HTTP)[[[302]]]]
-- [CODE(HTTP)[[[303]]]]
-- [CODE(HTTP)[[[307]]]]
-- [CODE(HTTP)[[[308]]]]
- [CODE(HTTP)@en[[[Location:]]]] [[ヘッダー]]
]FIG]
;; [23] [[状態符号]]は多数ありますが、 [[Fetch Standard]] によって自動的な[[リダイレクト]]が行われることとされているのは
[CODE(HTTP)[[[301]]]], [CODE(HTTP)[[[302]]]], [CODE(HTTP)[[[303]]]],
[CODE(HTTP)[[[307]]]], [CODE(HTTP)[[[308]]]] だけです。
* 意味
[14] [[リダイレクト]]は、[[対象資源]]のかわりに、別の [[URL]]
にアクセスするべきであることを表しています。
[15] その実際の意味は様々です。
[FIG(list)[
- [16] [[Webサイト]]構成の都合その他の理由により [[URL]]
([[ドメイン]]や [[path]] など) が変化した時に、旧 [[URL]]
でのアクセスを新 [[URL]] に誘導するために利用するのが主たる利用法です。
[CODE(HTTP)[[[301]]]] が最適な[[状態符号]]ですが、 [CODE(HTTP)[[[302]]]]
となっていることも多々あります。
- [17] [[鯖]]側[[Webアプリケーション]]などで [CODE(HTTP)@en[[[POST]]]]
を処理した後に、処理が反映されているページやその他関連するページなど、
[CODE(HTTP)@en[[[POST]]]] 操作の完了後に[[利用者]]に提示するべきページに遷移させるためによく使われます。
[CODE(HTTP)[[[302]]]] がよく用いられます。
- [18] 存在しない [[URL]] にアクセスしたときに、 [CODE(HTTP)[[[404]]]]
のかわりにトップページなどに[[リダイレクト]]することがあります。
ただしこの動作は [[URL]] の打ち間違いでも遷移して[[アドレスバー]]が書き換わってしまうなど、
[[利用者]]には不評で最近はあまり使われなくなっています。
- [19] [[Cookie]] などによる閲覧制限が行われている場合に、
閲覧権限を持たない[[クライアント]]からのアクセスを[[トップページ]]や[[ログインページ]]などに[[リダイレクト]]することがあります。
本来は [CODE(HTTP)[[[401]]]] や [CODE(HTTP)[[[403]]]] や [CODE(HTTP)[[[404]]]]
を使うべきなのでしょうが、[[利用者]]の便宜その他の理由でしばしば使われています。
- [20] [[captive portal]] で[[ログインページ]]に[[リダイレクト]]することがあります。
- [21] [[Semantic Web]] の世界では、[[資源]]の [[URL]] からその情報が含まれる
[[RDF]] ファイルへ [CODE(HTTP)[[[303]]]] [[リダイレクト]]を使うことになっています。
]FIG]
* 処理モデル
[539] 新旧の[[要求]]と[[応答]]は、互いに完全に独立したものです。 [[HTTP]]
プロトコルとしては状態は保持していません。新旧[[要求]]を異なる
[[HTTP接続]]を使って送信しても何ら問題ありませんし、
新旧[[要求]]の送信先の[[鯖]]がそもそも異なっているかもしれません。
* 相対 URL
[538] [CODE(HTTP)@en[[[Location:]]]] [[ヘッダー]]には[[相対URL]]
を指定することもできます。この値は[[実効要求URL]]を[[基底URL]]
として[[解決]]されます。
;; [CODE(HTTP)@en[[[Location:]]]] を参照。
* リダイレクトと要求メソッド
[11] [CODE(HTTP)[[[301]]]] と [CODE(HTTP)[[[302]]]] では、
[CODE(HTTP)@en[[[POST]]]] だった場合[[リダイレクト]]先では
[CODE(HTTP)@en[[[GET]]]] に書き換えます。それ以外の[[要求メソッド]]はそのまま保持します。
[12] [CODE(HTTP)[[[303]]]] では、[[リダイレクト]]先では
[CODE(HTTP)@en[[[GET]]]] に書き換えます。
[13] [CODE(HTTP)[[[307]]]] と [CODE(HTTP)[[[308]]]] では、
[[リダイレクト]]先でも[[リダイレクト]]前の[[要求メソッド]]をそのまま保持します。
[307] [[要求メソッド]]が[[安全]]でない場合、自動的な[[リダイレクト]]には注意する必要があります。
[[利用者]]は[[安全]]でない[[要求]]を[[リダイレクト]]してほしくないかもしれません。 [SRC[>>306]]
[308] [CODE(HTTP)@en[[[Location:]]]] があれば、
未対応の [CODE(HTTP)[[[3xx]]]] [[状態符号]]であっても、
自動的に[[リダイレクト]]して構いません [SRC[>>306]]。
[517] [[起源鯖]]は、 [CODE(HTTP)@en[[[PUT]]]] [[要求]]に対して[[対象資源]]の状態を変更せず、
他の[[資源]]に適用したい場合は、
適切な [CODE(HTTP)[[[3xx]]]] [[応答]]を送信し[['''なければなりません''']]。
その場合[[利用者エージェント]]は[[リダイレクト]]に従うか選ぶことができます。 [SRC[>>518]]
;; [22] 現状 [[Fetch Standard]] では[[リダイレクト]]前後の[[要求メソッド]]の変化を規定していません。 [TIME[2014-09-04T14:34:24.200Z]]
* リダイレクトとヘッダー
[7] [[リダイレクト]]前後で指定するべき[[ヘッダー]]の同一性や差異について特に規定はありません。
[8] [[RFC 7231]] は[[ヘッダー]]の仕様書に対し、[[リダイレクト]]前後で保持するべきか明記することを検討するよう求めています
[SRC[>>6]]。
* リダイレクトループ
[535] [[鯖]]は、[[リダイレクト]]先として[[リダイレクト]]を返す [[URL]]
を指定しても構いません。
[536] [[利用者エージェント]]は[[リダイレクト]]により[[要求]]を改めて送信した結果が[[リダイレクト]]の場合も、
更にその[[リダイレクト]]に従うことが期待されています。
[523] [[クライアント]]は、[[リダイレクト]]の循環を検出して対処する[['''べきです''']]
[SRC[>>518]]。
;; [524] なぜ [['''MUST''']] でなく [['''SHOULD''']] なのか謎です。
無限[[リダイレクト]]で[[無限ループ]]するような[[クライアント]]はどう考えてもバグっており、
有害でしかありません。
;; [525] [[RFC 2068]] は最大5回までとしており、注意が必要 [SRC[>>518]] です。
* 素片識別子
[540] [[素片識別子]]が適切で無い場面もあるとして、
[CODE(HTTP)[[[201]]]] を例に挙げています [SRC[>>534]] が、
なぜか禁止はされていません。また [CODE(HTTP)[[[201]]]]
以外にも不適切な場面が存在することを暗示していますが、
実際に何が該当するのかは不明です。
[537] [[利用者エージェント]]は、[CODE(HTTP)[[[3xx]]]] [[応答]]の
[CODE(HTTP)@en[[[Location:]]]] に[[素片識別子]]が含まれていない場合、
[[要求対象]]を[[生成]]するのに使った[[URL]]の[[素片識別子]]を継承するものとして処理しなければ[['''なりません''']]
[SRC[>>534]]。
[41] <http://foo.example/bar#fragment1> を取り寄せる時に、次のようになったとします。
[PRE[
C: GET /bar HTTP/1.1
C: Host: foo.example
C:
S: 302 Found HTTP/1.1
S: Location: http://foo.example/hoge
S:
]PRE]
この時、 [[UA]] の望ましい動作は、 ([[WWWブラウザ]]であれば)
<http://foo.example/hoge> を要求し、その #fragment1 を表示することです。
[42] 同じ例で、次のような応答があったとしましょう。
[PRE[
S: 302 Found HTTP/1.1
S: Location: http://foo.example/hoge#fragment2
S:
]PRE]
この時 WWW ブラウザは、 <http://foo.example/hoge#fragment2>
を表示し、 #fragment1 のことは忘れます。
[44] >>42 で、「アドレス・バー」のような [[UI]] 部分をどうするかという問題がありますね。
[[301]] なら新しい (#fragment2 の) URI にしてしまえばいいですが、 [[307]]
の時はどうなんでしょう。元の #fragment1 にしておくのと、 #fragment*
は削ってしまうのと2種類考えられますが。
[43] 但し実際には、この #fragment の扱いについては仕様・実装がぐちゃぐちゃです。
できることならば [CODE[Location]] 欄で素片識別子を使わないといけないようなことにならないようによく考えておくべきでしょう。[WEAK[それでも使わざるを得なくなったときは仕方ないですし、 UA の挙動なんて飾りです、偉い人には分からなくて結構と開き直るのも場合によってはありでしょう。]]
** 仕様書の類の言及
[24] >>20,>>5 [[RFC2396]] ([[URI]]) によると [CODE(ABNF)[absoluteURI]] は [CODE(ABNF)[fragment]] を含みません。従って [[HTTP/1.1]] と CGI で仕様が不整合な気がします。
実際のところ [CODE[fragment]] つき URI を送っても多くの URI は解釈する気がしますが、仕様的には無理ということでいいですか?
[35] >>24 ''HTTP/1.1 Specification Errata''
[DEL[<http://world.std.com/~lawrence/http_errata.html#location-fragments>]] [INS[<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.
[CODE[Location]] URL 中での素片識別子が適切でない場面があります。
- [[201]] Created (作成しますた) 応答。 [CODE[Location]]
頭を使用して作成された資源全体を URL を指定するものだから。
- [[300]] Multiple Choices (複数選択肢)。選択決定は資源の性質についてなされるもので素片の性質についてではないから。
- [[305]] Use Proxy (串使って)。
現在、元の URI に素片がある場合、例えば
<http://host1.example.com/resource1#fragment1> で [SAMP[/resource1]]
が <http://host2.example.com/resource2#fragment2>
に redirect している時に「fragment1」は捨てられているのでしょうか?
[SAMP[fragment2]] を探してそれから [SAMP[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] [CITE@en[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]]
( ([TIME[2011-07-24 11:28:00 +09:00]] 版))
<http://html5.org/tools/web-apps-tracker?from=6321&to=6322>
[311] [CITE@en[URL Fragments and Redirects - EricLaw's IEInternals - Site Home - MSDN Blogs]]
( ([TIME[2011-07-24 12:07:00 +09:00]] 版))
<http://blogs.msdn.com/b/ieinternals/archive/2011/05/17/url-fragments-and-redirects-anchor-hash-missing.aspx>
[312] [CITE@en[[[draft-bos-http-redirect-00]] - Handling of fragment identifiers in redirected URLs]]
([TIME[2011-08-17 18:10:19 +09:00]] 版)
<http://tools.ietf.org/html/draft-bos-http-redirect-00>
[10] [[RFC 7231]] は、[[リダイレクト]]によって元の [[URL]]
に指定されていた[[素片識別子]]をリダイレクト先の [[URL]]
の[[文書]]が読み取れることによる情報漏洩の危険があることを指摘しています [SRC[>>9]]。
** 実装について
[58]
[[WinIE 6.0]] (もしかしたら以前の版も。) は redirect された時の [CODE(HTTP)[Location]] URI 参照に素片識別子がついていると直後の再要求時にその素片識別子ごと [CODE(ABNF)[Request-URI]] にして送ってしまうみたいです。
([[名無しさん]] [WEAK[2004-05-03 04:37:14 +00:00]])
* HTTP 以外の URL
@@ ...
* リダイレクトの開始
[543] [[HTTPリダイレクト]]は、[[応答]]の直後に[[リダイレクト]]後の[[要求]]が送信されることを期待しています。
[544] 仕様上は[[応答]]から[[要求]]までの待ち時間を [CODE(HTTP)@en[[[Retry-After:]]]]
[[ヘッダー]]で指定できることになっていますが、実装されていませんし、
今後実装される見込みもなさそうです。
[545] 一旦何らかのページを表示して、すこし待ってから別のページを表示したいときは、
[CODE(HTML)@en[[[Refresh]]]] を利用できます。
[309] [[WinIE8]]、[[Opera]]、[[Chrome]]、[[Firefox]] のどの [[Webブラウザー]]も、
[[リダイレクト]]している [[HTTPメッセージ]]全体が到着するのを待たず、
[[頭部]]を受け取り次第すぐに[[リダイレクト]]先の [[URL]]
の取得をはじめるようです。
;; <http://suika.fam.cx/~wakaba/-temp/test/http/redirect/delayed.cgi> ([[頭部]]はすぐに返すものの、[[応答本体]]の生成が終わるまで100秒かかる例)。
;; [CODE(HTTP)@en[[[Location:]]]] [[頭欄]]を受け取り次第すぐに次に進むのか、
[[頭部]]をすべて受け取り終わるまで進まないのかは未検証です。
* 歴史
[519] [[リダイレクト]]には、元々の[[要求]]の[[要求対象]]を書き換え、
[[要求メソッド]]を維持するパターンと、[[要求メソッド]]を [CODE(HTTP)@en[[[GET]]]]
に書き換えるパターンがあります。
[520] [[HTTP]] 仕様書の著者の意図は、 [CODE(HTTP)[[[301]]]] と [CODE(HTTP)[[[302]]]]
は前者とするものでしたが ([[CERN]] の実装もそうなっていました)、
実際には [CODE(HTTP)[[[303]]]] 共々後者の動作とする実装があり、
やがて後者に収束していきました。 [SRC[>>306]]
[521] このため後者の意味の [CODE(HTTP)[[[307]]]] が新たに追加されました。
更に、[[要求メソッド]]が [CODE(HTTP)[[[POST]]]] だった場合のみ、
[CODE(HTTP)[[[301]]]] と [CODE(HTTP)[[[302]]]] で前者の動作でも[[適合]]することとされました。
[SRC[>>306]]
;; [522] [[HTTP]] の仕様書の著者の意図としては、依然として [CODE(HTTP)[[[301]]]]
と [CODE(HTTP)[[[302]]]] は元の[[要求メソッド]]のまま[[リダイレクト]]するのが正しい使い方のようです。
15年以上にわたり安定している現在の慣習と互換性のない“理論上は正しい”
方式にこだわり続ける意図が何なのかは謎です。 [[Webブラウザー]]も[[鯖]]側の
[[Webアプリケーション]]も、 [CODE(HTTP)[[[301]]]] や [CODE(HTTP)[[[302]]]]
で[[要求メソッド]]が保持されることなど想定しておらず、
そうでない実装方法は決して[[Web互換]]では無いのですが・・・。
* 実装
[1] [CITE@ja[リダイレクトの設定とインデックスに登録されるURL - インフォセンター - Yahoo!検索]]
([TIME[2010-05-25 10:35:59 +09:00]] 版)
<http://info.search.yahoo.co.jp/archives/002865.php>
* 関連
[3] 通常は [[HTTPリダイレクト]]とは呼びませんが、 [CODE(HTTP)@en[[[Refresh:]]]]
[[ヘッダー]] (や [CODE(HTML)@en[[[<meta http-equiv=refresh>]]]] も[[リダイレクト]]を実現するものです。
[4] また[[リダイレクト]]には [[JavaScript]] によって[[クライアント]]側で実行する手法もあります。
[5] [[HTTP]] の仕様書は、 [CODE(HTTP)[[[300]]]] や [CODE(HTTP)[[[304]]]]
も[[リダイレクト]]と呼んでいます。
;; [CODE(HTTP)[[[3xx]]]] の項を参照。
[542] [CODE(HTTP)[[[201]]]] でも [CODE(HTTP)@en[[[Location:]]]]
を使いますが、本項の[[HTTPリダイレクト]]とは異なります。
[541] [[HTTP]] には他に [CODE(HTTP)@en[[[Content-Location:]]]] や
[CODE(HTTP)@en[[[Link:]]]] もありますが、本項の [[HTTPリダイレクト]]とは異なります。
[526] [[CGI]] には[[局所リダイレクト応答]]と[[クライアントリダイレクト応答]]がありますが、
[[クライアントリダイレクト応答]]が[[HTTP応答]]における[[リダイレクト]]に相当します。
* メモ
[527] [CITE[Response.redirect() > new RedirectResponse() · a083a27 · whatwg/fetch]]
( ([TIME[2014-06-04 07:55:35 +09:00]] 版))
<https://github.com/whatwg/fetch/commit/a083a27c53a65e5ba93c486401fb55c2a68a7cd3>
[528] [CITE@en[HTTP - WHATWG Wiki]]
( ([TIME[2014-08-05 06:24:41 +09:00]] 版))
<http://wiki.whatwg.org/wiki/HTTP#Redirects>
[529] [CITE@en[HTTP Methods and Redirect Status Codes - IEInternals - Site Home - MSDN Blogs]]
( ([TIME[2014-08-25 14:22:36 +09:00]] 版))
<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] [CITE@en[598304 – XHR rewrites non-POST methods upon 301/302 redirects]]
( ([TIME[2014-08-25 14:27:20 +09:00]] 版))
<https://bugzilla.mozilla.org/show_bug.cgi?id=598304>
[531] [CITE@en[676059 – Make redirect prompting depend on HTTP-safeness of method, not presence of request body]]
( ([TIME[2014-08-25 14:28:27 +09:00]] 版))
<https://bugzilla.mozilla.org/show_bug.cgi?id=676059>
[532] [CITE[Test Cases for HTTP Redirects]]
( ([TIME[2014-07-27 13:47:16 +09:00]] 版))
<http://greenbytes.de/tech/tc/httpredirects/>
[533] [CITE[Bug 60440 – ''''''[''''''Qt'''''']'''''' Redirection of HTTP POST (3xx) incorrectly includes original POST data]]
( ([TIME[2014-08-25 14:34:12 +09:00]] 版))
<https://bugs.webkit.org/show_bug.cgi?id=60440>
[330] [[au]] の[[ガラケー]]だと[[素片識別子]]が入っていると [CODE(HTTP)@en[[[404]]]] になります。
[406] [CITE[Location: javascript:alert(1) が返ってきた時のブラウザの動作 - Qiita ''''''[''''''キータ'''''']'''''']]
( ([TIME[2013-10-31 03:05:25 +09:00]] 版))
<http://qiita.com/ooooooo_q/items/1f0c2c64413495c46e6b>
[410] [CITE@en[HTTP - WHATWG Wiki]]
( ([TIME[2013-12-19 01:12:07 +09:00]] 版))
<http://wiki.whatwg.org/wiki/HTTP#Location_header>
[423] [CITE@en[URL Fragments and Redirects - IEInternals - Site Home - MSDN Blogs]]
( ([TIME[2014-08-31 15:42:14 +09:00]] 版))
<http://blogs.msdn.com/b/ieinternals/archive/2011/05/17/url-fragments-and-redirects-anchor-hash-missing.aspx>