LoginSignup
4

More than 1 year has passed since last update.

posted at

updated at

Organization

特定の条件でのみS3の画像URLでCORSエラーが発生する問題をなんとかする

 要約

  • S3に保存した画像URLに対してCloudFront経由でブラウザからアクセスする処理が2種類ある
    • 1つはHTMLのimgタグで呼び出す場合
    • もう1つはJavaScriptのnew Image()などでImageElementを操作する場合
  • S3とCloudFrontの両方でAccess-Control-Allow-OriginHeaderを正しく設定しているのにJavaScript上で操作する時にCORSエラーが発生したりしなかったりする現象が発生
  • S3の画像URLを使用している場合、かつ、Chromeでブラウザのcacheが有効になっている場合、2度目のアクセス時にAccess-Control-Allow-OriginHeaderの付いていないキャッシュしたレスポンスをChromeが返すためCORSエラーが発生してしまう

問題が発生してたコード

  • 次のように同じ画像URLに対してHTMLのimageタグで使用、かつJavaScript上でも同じ画像に対して処理を行おうとしていた
<img src="https://hoge.cloudfront.net/fuga.jpeg">
const image = document.createElement('img');
image.src = "https://hoge.cloudfront.net/fuga.jpeg"

しかし、JavaScript上のコードで次のようなCORSエラーが発生したりしなかったりする現象が発生した

Access to image at 'https://hoge.cloudfront.net/fuga.jpeg' from origin 'https://hoge.cloudfront.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

S3やCloudFrontの設定の問題?

  • 調べていたところ、S3やCloudFrontでAccess-Control-Allow-OriginHeaderが設定されていない場合のケースが出てきたのですが、既に設定済みだった
    • そもそもHTML上では問題なく使えているので、JavaScript上でだけ発生する理由が説明できない・・・
  • ちなみに未設定の場合は次のように設定できる
  • document.getElementById()でHTMLの画像タグを取得してJavaScript上で使うようにしたら発生頻度は下がったようだったが、それでも人によっては発生したり発生し続けていて原因が突き止めずにいた

そしてようやく原因を突き止める

解決策という名の応急処理

  • ブラウザ側の挙動の問題なので対応するのがなかなか難しい・・・
  • 上記の記事ではAWS LambdaでHeaderを変更する関数を間に挟むようにして対処していたようだが、そのためだけのLamdaを用意するのは手間がかかるので別の方法を検討
  • HTMLとJavaScriptで使用する画像URLが同じだとキャッシュされてしまうので、URLの末尾にランダムなクエリパラメーターを追加して使用すれば毎回別のURLになりキャッシュを利用されないのではと考えた
  • 今回の場合はバックエンドサーバーからS3の署名付きURLを発行して使用しており、そこにオリジナルのクエリパラメーターを追加すると400エラーになってしまった
  • S3の署名付きURLにはExire(有効期限)パラメーターがついており、1秒ごとに更新されるので、HTMLで使用される画像URLとは別にJavaScript上で使用する画像URLを1秒ずらして取得するようにして対応した
  • 他に良い対応方法があれば教えてください :pray:

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4