fetch APIのredirect関連メモ
HTTPS環境下で特定のURLからデータを取得するときに、リソースがHTTPで配信されていた場合、当たり前だけどMixed Content警告が発生する。
fetch('http://www.yahoo.co.jp/'); // こんなのが出力される // Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure resource 'http://www.yahoo.co.jp/'. This request has been blocked; the content must be served over HTTPS. // Fetch API cannot load http://www.yahoo.co.jp/. Failed to start loading.(anonymous function) // Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: TypeError: Failed to fetch // Uncaught (in promise) TypeError: Failed to fetch(…)
基本的にはHTTPS以外のものは呼ばない、CSPなどを利用してそもそもHTTPのリソースがブロックしてしまうといった解決策が存在するが、HTTPSのURLがHTTPのURLにリダイレクトする場合はどうすればよいのだろうか。
$ curl -I https://example.com HTTP/1.1 302 Found Content-Type: text/html; charset=UTF-8 Location: http://other-domain.com Content-Length: 261
HTTPSからHTTPにリダイレクトなんてないだろ、と思ったりもするが、後方互換性を重視した開発の現場では稀にそういうことがある。IDの若い特定のユーザには古いページを表示する、古いページはHTTPSに対応していないといった状況などがそれにあたる。
fetch
APIはredirectオプションによってリダイレクト時の振る舞いを制御できる。
redirect: The redirect mode to use: follow (automatically follow redirects), error (abort with an error if a redirect occurs), or manual (handle redirects manually). In Chrome the default was follow before Chrome 47 and manual starting with Chrome 47.
A request has an associated redirect mode, which is "follow", "error", or "manual". Unless stated otherwise, it is "follow".
w3cのspecにも未設定の場合はfollow
が選択されるとあるし、実際の振る舞いもリダイレクトしてリソースを取得している。オプションの振る舞いをまとめると、2016年10月現在では以下のようになる。
- follow
- デフォルト. リダイレクト先まで追従してリソースの取得を行う
- error
- リダイレクトが発生した場合にネットワークエラーを投げる
- manual
- 手動でリダイレクトを制御する。このときResponseオブジェクトは opaqueredirect となる。opaqueredirectは、レスポンス内容が隠蔽された状態のオブジェクトで、実際のレスポンスはinternal responseにアクセスする必要がある(この辺りは検証不十分)
つまり、今回のようにHTTPS→HTTPへのリダイレクトが行われ得るリソースに関しては、redirect
オプションにmanual
を渡してあげれば一応mixed content警告は回避できそう。
fetch('https://redirect-to-http-resource.com', {redirect: 'manual'}) .then(res => { // do something });