ActiveStorage+Amazon S3で管理している画像をフロント側で扱うときのCORSまわりでハマったことめも
みんなでつくるダンジョンのテストサーバはHeroku+Amazon S3で構成しており、画像の管理まわりにはActiveStorage(Ruby on Rails)を使っていますが、テストサーバに上げても「うまくうごかない~」となっていたのでした。
S3上にある画像をImageオブジェクトで取得して、Canvasをつかって加工するというJavaScriptプログラムを組んでいました。
let url = "https://s3.example.com/hoge.png"; let image = new Image; image.crossOrigin = "anonymous"; // オリジン間のリクエストだよーということを伝えるために必要 image.onload = () => { let canvas = document.createElement("canvas"); やりたい処理 } image.src = url;
これで画像が取得できてめでたし、と思っていたのですが、ブラウザ上にはこんなエラーメッセージが出てしまっていました(URLまわりは実際のものとは異なります)。
Access to Image at 'https://s3.example.com' from origin 'https://heroku.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://heroku.example.com' is therefore not allowed access.
Access-Control-Allow-Origin
がうまく設定されていないとのこと。実際にブラウザのデベロッパーツールを確認してみても、確かに Access-Control-Allow-Origin
ヘッダが画像のレスポンスにありません。
(Amazon S3とみんなでつくるダンジョンのテストサーバ(=heroku)は異なるオリジンとなるので、リソースを共有するときにはCORSの設定(Access-Control-Allow-Origin
)が必要)
もちろんS3のCORS設定は実施済みです。
ActiveStorageで管理しているリソース(今回の場合は画像)を先ほどのJavaScriptプログラムで参照するために、 Railsサーバ側で url_for
関数を使ってリソースのURLをつくるのですが、ここでつくったURLはRailsサーバを向いています。このURLにアクセスするとリダイレクトがかかり、S3を参照するURLが返されます。
S3はリクエストにOriginヘッダがないと Access-Control-Allow-Origin
ヘッダ情報を返してくれませんが、リダイレクトによってこの辺がうまくいっていないのでは?と思ったのでした。
そこで、先ほどのプログラムを以下のようにしてみます。Imageタグでリダイレクトを受けるのではなく、一度fetchをつかってリダイレクト先のURLを受け取り、そこからImageオブジェクトで画像を取得します。
let url = "https://s3.example.com/hoge.png"; fetch(url).then( response => { let image = new Image; image.crossOrigin = "anonymous"; image.onload = () => { let canvas = document.createElement("canvas"); やりたい処理 } image.src = response.url; });
これで無事にS3からくる画像レスポンスに Access-Control-Allow-Origin
ヘッダが付与されてJavaScript上で画像を参照できるようになりました。めでたしめでたし。
ではでは~。