銀色うつ時間

思い出すたび何か胸につっかえてるだけ

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オプションによってリダイレクト時の振る舞いを制御できる。

developer.mozilla.org

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.

Fetch Standard

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
  });