前回「CarrierWave」を使って AWS S3 にファイルをアップロードをしましたが、
S3 にアップロードしたファイルは、AWS CloudFront を使って配信するのがベターみたいです。
今回は、AWS CloudFront を介したファイルダウンロードを作ってみます。
目次
参考
- AWS - 署名付き URL の使用
- AWS - 署名付き URL と署名付き Cookie (信頼された署名者) の作成が可能な AWS アカウントの指定
- Class: Aws::CloudFront::UrlSigner
- Developers.IO - CloudFront+S3 で署名付き URL でプライベートコンテンツを配信する
- Qiita - CloudFront の署名付き URL を Ruby で発行する
AWS の設定
CloudFront 用キーペア取得
AWS マネジメントコンソールにログインします。
アカウントメニューを開いて「マイセキュリティ資格情報」を開きます。
(ここは、公式だと[account-name] メニューで、[Security Credentials]をクリックとなっています。)
「CroudFront のキーペア」という項目を開いて「新しいキーペアの作成」をします。
プライベートキーファイル、パブリックキーファイルのダウンロードができるのでそれぞれダウンロードしておきます。
私は、後に作成する Rails アプリケーションの、アプリケーションルートに保存しておきました。
プライベートキーは「pk-」、パブリックキーの方は「rsa-」から始まるファイルでした。
作成が終わるとアクセスキー ID が表示されるようになるので、こちらも控えておきます。
CloudFlont 設定
AWS マネジメントコンソールで、CloudFront の設定画面を開きます。
AWS マネジメントコンソールの「ネットワークとコンテンツ配信」という項目にリンクがあります。検索でもいいです。
「Create Distribution」をクリックします。
Web と RTMP がありますが、Web 側の「Get Started」をクリックします。
「Origin Domein Name」をクリックすると、ログインしている AWS のアカウントが所有している S3 のバケットが表示されるので、それを選びます。
Restrict Viewer Access(Use Signed URLs or Signed Cookies)を「Yes」に変更します。
以上ができたら、一番下の「Create Distribution」をクリックします。
作成後すぐには使えないので、しばらく待ちます。
CloudFront 設定画面で現在のステータスが「In Progress」から「Deployed」に変わるまでの間待つことになります。(ざっくり 15 分くらい待ちました。)
後で使うので Domain Name の項目を控えておきます。
ID の項目をクリックして、作成した CloudFront Distribution の詳細を開きます。
Origin の中から選択して、Edit を押します。
Restrict Bucket Access を「Yes」、Grant Read Permissions on Bucket を「Yes」にして「Yes, Edit」を押します。
ここまでで AWS マネジメントコンソールでの操作は終了です。
Rails で実装
今回は、前回記事のRails でファイルのアップロードとダウンロードの「CarrierWave」を使用した S3 へのアップロードを改変します。
そちらも参考ください。
CarrierWave で実装してダウンロードをする仕組みを作ったとき、コントローラーのダウンロードメソッドは以下のようにしてました。
こちらを改変して、CloudFront からファイルを受け取るようにします。
1 | def download |
パッケージ導入
Gemfile に以下を追記して、bundle install
を実行してインストールします。
1 | gem 'aws-sdk-cloudfront' |
コントローラのメソッドの修正
以下のように改変しました。
1 | def download |
参考:ビューの作成
ダウンロード処理を要求するビューは以下の通りです。
1 | <p id="notice"><%= notice %></p> |
確認
以上ができたら、rails s
で実行して該当のページでダウンロードします。
ダウンロードできたでしょうか?
正直言ってダメでした。
リダイレクトした先へページ遷移してしまいました。
意図した動作ではないのが痛いところです。
ただ、表示されたとき URL を見るとアドレスがhttps://XXXXXXXXXXXXX.cloudfront.net/
から始まるようになったのではないでしょうか。
CloudFront から署名付き URL を要求するという目標は達成できました。
それでもダウンロードを僕はしたいんだ
それでもダウンロードはしたいので、調べます。
参考
- Forcing Download from s3 amazon servers
- S3 オブジェクトにメタデータを追加する方法
- carrierwave で S3 にアップロードする際にアップローダー毎にメタデータを設定する
- Qiita - jQuery でリンクをクリックさせたい時
どうやら、レスポンスヘッダーに'Content-type: application/force-download'
が付いているとよいそうです。
S3 にはアップロードしたファイル(オブジェクトと言っていたりどっち?)は、レスポンスヘッダーのカスタマイズができます。
この設定は「CarrierWave」でファイルアップロード時に適用可能です。
アップローダーを編集してゆきます。
アップローダーの編集
app/uploaders/icon_uploader.rb に以下を追記します。
1 | def fog_attributes |
追記したものは以下の通りです。コメントはすべて削ってあります。
1 | class IconUploader < CarrierWave::Uploader::Base |
コントローラーの修正
以下のように取得した URL を json で返すように変更します。render json: {url:signed_url}
の部分です。
1 | def download |
ビューの修正
ダウンロード処理を要求するビューを書き換えます。
ポイントは、<%= link_to 'ダウンロード',download_icon_path(@account),id: 'downloadfile' %>
と script タグ内です。
link_to で作成される a 要素に id を割り当てて、クリックした際に jQuery で処理させます。
コントローラーから帰ってきた署名付き URL を割り当ててきた a 要素を jQuery で発火させて、ダウンロードさせる仕組みです。
1 | <p id="notice"><%= notice %></p> |
確認
以上ができたら、rails s で実行してファイルのアップロードから行います。
``’Content-type: application/force-download’`が設定されているのは、アップローダーの編集をした以後アップロードしたファイルだけです。
それ以前のファイルはページ遷移するはずです。
必要で有れば AWS マネジメントコンソールで S3 の設定をすればよいでしょう。
今度はダウンロードできました。
問答無用でファイルはダウンロードされるようになりました。
今回は「CarrierWave」を使用して AWS S3 にアップロード、AWS CloudFront を介してファイルのダウンロードをやってみました。
AWS マネジメントコンソールが急に英語のみの管理画面になったりしますが、根気よく進めましよう。
ではでは。