LoginSignup
4
0

More than 1 year has passed since last update.

社内で話したメディアダウンロード機能の実装について

Last updated at Posted at 2022-12-06

背景

最近、社内でS3に保存したメディアをHTML上で手元にダウンロードする機能を実装してほしいとの要望があった。
実際に作成していく中で、私の知識不足もあり、いろいろ嵌っていったので、共有と備忘録も込めて、この記事を記述する。

なんだ、簡単じゃん

調べてみると下記のようなコードで実装できるらしい!(やったね!)

<a href="https://image-test.s3.amazonaws.com/test.png" download>ダウンロード</a>

うっきうきで実装してみると...
image.png
違う、そうじゃない...
調べてみると、下記のような文言がありました。

この属性は同一オリジンのURLに限り動作する

今回、ダウンロードしたい画像はS3に置いてあるため、当然のことながら同一ドメインではない。よくリファレンスを読んでみる。
image.png

どうやらcontent-dispositionを設定しなければならないみたい。
というわけで、content-dispositionを付けてみよう!

準備

今回行ったことは以下の三つである。

  1. S3にメディアを保存するときに拡張子を指定する
  2. content-dispositionを設定する
  3. CORS対応を行う

画像はS3を保存しており、違うドメインのHTMLで画像をダウンロードさせるために上記の三つが必要となる。

1. S3にメディアを保存するときに拡張子を指定する

今回は簡単なスクリプトでrubyで記述する。
実際にはメディアをアップロードするだけでいいのだが、aws-cliでrubyから作ってみる

content_type.rb
require 'aws-sdk'
require 'mime/types'
require 'httpclient'

file_name = "test.jpeg"
region = "ap-northeast-1"
bucket_name = image-test

file = File.read(file_name)
File.write("test", file)

s3 = Aws::S3::Resource.new(region: region)
obj = s3.bucket(bucket_name).object(file_name)

obj.put(
  body: file,
  content_type: 'png'
)

2.content-dispositionを設定する

そもそもcontent-dispositionってなんぞや?となっていた。
調べてみると、下記の通り。

コンテンツをwebページの一部として表示するかダウンロードするかを示します。
inline を指定すればwebページとして、attachment を指定すればダウンロードファイルとして、を表します。 また、filenameパラメータで、ファイルの初期名を指定できます。

なるほど、それでは、実際にメディアをgetする時に指定してみよう!
設定するaws-cliは以下の通り

presigned_url.rb
require 'aws-sdk'

file_name = "test.jpeg"
region = "ap-northeast-1"
bucket_name = image-test

s3client = Aws::S3::Client.new(
    region: region,
    credentials: '~/.aws/config',
)

signer = Aws::S3::Presigner.new(Client: s3client)

puts signer.presigned_url(
    :get_object,
    bucket: bucket_name,
    key: file_name,
    expires_in: 3600,
    response_content_disposition: "attachment; filename=#{file_name}"
)

3.CORSを設定する

今回、AWSのS3に保存しているメディアについて、presigned_urlを発行し、ダウンロードページに渡すことを想定する。
そのため、使用されるメディアのCORS対応を行わなければ、HTMLでダウンロードしようとしたときに引っかかるため、この設定を行う。
AWS S3では、バケットのアクセス許可のタブから下記の場所にCORSの設定を施すことができる。
スクリーンショット 2022-12-05 230322.jpg
exposeHeadersにContent-Dispositionをセットして準備完了!!

実行

まず、presigned_urlを発行する。
先ほどのコードを実行してS3にメディアをアップロードする。

実行
ruby content_type.rb

今回は、拡張子pngで試してみよう。
次に、このメディアをダウンロードするためのpresigned_urlを発行する。

実行
ruby presigned_url.rb 

あとはこのURLをHTMLのボタンに組み込む。
本当はAPIを作成して都度presigned_urlができるようにしたいが、今回は直に入力する。

<a href="実行した結果のpresigned_url">ダウンロード</a>

すると...?

image.png

ボタンを押したらダウンロードできた!!
これで目的を達成!!

気を付ける嵌りポイント

メディアのcontent-typeを指定しないと...?

binary/octet-streamというcontent-typeになる。
これが厄介で、binary/octet-streamのファイル名をtest.pngとかにしてダウンロードすると、凡そ全てのブラウザでダウンロードできる、iPhone君だけはきちんとbinary/octet-streamのファイルとして処理されてしまう...
やはり、content-typeはしっかりと指定しよう!!

まとめ

content-dispositionという、メディアをダウンロードするかどうかをヘッダーに付与することで、メディアをダウンロードする機能を実行できます。
他にもやり方がたくさんあるかもしれないが、awsなど別ドメインを介してダウンロードする場合、参考になればと思います。

参考

4
0
0

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
  3. You can use dark theme
What you can do with signing up
4
0