t-sanoブログ

メモです。マイペースにアウトプットします。

S3に大容量ファイルを直接アップロードする(署名付きURL + マルチパートアップロード)

ubw.hatenablog.com

前回、署名付きURLを利用し、S3に対してファイルを直接アップロードできることを確認した。 この方法で、curlコマンドで大容量のファイルがアップロードできることも確認した。 ブラウザからも200MB程度のファイルをAJAXでアップロードできることを確認した。

しかし、300MBのファイルがブラウザからアップロードできず。。。 何か設定が足りていない・・・? どうやら調べていると、大容量ファイルのアップロードはマルチパートアップロードを推奨しているとのこと。

そこで、署名付きURL + マルチアップロードを試してみることにした。

目的

クライアントは署名付きURLを利用してファイルをマルチパートアップロードする

環境

構成

f:id:t-sanox:20160814161940p:plain

処理の流れ

  1. create_multipart_upload
  2. 署名付きURLの生成(ファイル分割数だけ)
  3. partsの取得
  4. complete_multipart_upload

やり方

前提として、AWSの設定は前回と同じように実施した。

1. create_multipart_upload

upload_id等を発行する。upload_idは署名付きURLを発行する際に利用する。

s3 = Aws::S3::Client.new
uploader = s3.create_multipart_upload(bucket: bucket_name, key: key)

2. 署名付きURLの生成(ファイル分割数だけ)

分割してアップロードするファイルの数だけ署名付きURLを発行する。

presigner = Aws::S3::Presigner.new
urls = []
(1..part_number).each do |num|
  urls.push(
    presigner.presigned_url(:upload_part,
                            bucket: uploader.bucket,
                            key: uploader.key,
                            upload_id: uploader.upload_id,
                            part_number: num))

3. partsの取得

署名付きURLでのアップロード完了後に実施する。 マルチアップロードの完了には、etagとpart_numberが必要になる。 下記コードで、マルチアップロードのpart一覧から、etagとpart_numberを取得する。

parts = []
parts_info = s3.list_parts(bucket: uploader.bucket_name, key: uploader.key, upload_id: uploader.upload_id).parts
parts_info.each do |part|
  part_info = { etag: part.etag, part_number: part.part_number }
  parts.push(part_info)
end

4. complete_multipart_upload

マルチアップロードを完了する。 完了させないと、ファイルはS3バケットに表示されない。

s3.complete_multipart_upload(
  upload_id: uploader.upload_id,
  multipart_upload: parts,
  bucket: uploader.bucket_name,
  key: uploader.key
)