aws が提供するコマンドラインツールの aws cli を使って、S3オブジェクトのContentTypeを設定する方法をメモ。
aws s3 cp の場合
default
aws s3 cp
コマンドを使うと、デフォルトでは ContentType が guess される。
$ aws s3 cp song.mp3 s3://02a8/song.mp3 upload: ./song.mp3 to s3://02a8/song.mp3 $ aws s3api head-object --bucket 02a8 --key song.mp3 { "LastModified": "Tue, 13 May 2014 15:19:57 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" }
guess の仕様は Python 標準ライブラリー の mimetypes.guess_type
に準拠。
guess 例
$ python Python 2.7.3 (default, Aug 1 2012, 05:14:39) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import mimetypes >>> mimetypes.guess_type('foo.mp3') ('audio/mpeg', None) >>> mimetypes.guess_type('foo.json') ('application/json', None)
ContentType の guess をやめる
--no-guess-mime-type
をつけて cp する。
$ aws s3 cp --no-guess-mime-type song.mp3 s3://02a8/noguess.mp3 upload: ./song.mp3 to s3://02a8/noguess.mp3 $ aws s3api head-object --bucket 02a8 --key noguess.mp3 { "LastModified": "Tue, 13 May 2014 15:21:32 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "binary/octet-stream", "ContentLength": "0" }
ContentType を明示的に指定
--content-type
で明示的に指定して cp する。
$ aws s3 cp --content-type text/plain song.mp3 s3://02a8/text_plain.mp3 upload: ./song.mp3 to s3://02a8/text_plain.mp3 $ aws s3api head-object --bucket 02a8 --key text_plain.mp3 { "LastModified": "Tue, 13 May 2014 15:22:32 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "text/plain", "ContentLength": "0" }
別バケットからコピーした時の挙動
コピー元がローカルのファイルシステムではなく、S3 オブジェクト(すでに Content-Type を持っている)だったらどうなるのか?
$ aws s3 cp --no-guess-mime-type s3://02a8/text_plain.mp3 s3://02a8/cp_noguess.mp3 copy: s3://02a8/text_plain.mp3 to s3://02a8/cp_noguess.mp3 $ aws s3api head-object --bucket 02a8 --key cp_noguess.mp3 { "LastModified": "Tue, 13 May 2014 15:54:04 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "text/plain", "ContentLength": "0" } $ aws s3 cp --content-type text/html s3://02a8/text_plain.mp3 s3://02a8/cp_text_html.mp3 copy: s3://02a8/text_plain.mp3 to s3://02a8/cp_text_html.mp3 $ aws s3api head-object --bucket 02a8 --key cp_text_html.mp3 { "LastModified": "Tue, 13 May 2014 15:54:14 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "text/plain", "ContentLength": "0" }
--no-guess-mime-type
オプションをつけようと --content-type
オプションをつけようと、コピー元の ContentType が引き継がれる。
aws s3 sync の場合
動きは aws s3 cp
の時と同じ。
- sync 元がローカルのファイルシステムの場合、デフォルトで ContentType は guess され、
--no-guess-mime-type
や--content-type
で guess を上書きできる。 - sync 元が S3 オブジェクトの場合(バケット間コピーとか)、コピー元の ContentType がそのまま引き継がれる。
上で 02a8 バケットに作成したオブジェクトを 02a9 バケットに aws s3 sync
してみると
$ aws s3 sync s3://02a8 s3://02a9 copy: s3://02a8/copied_song.mp3 to s3://02a9/copied_song.mp3 copy: s3://02a8/song.mp3 to s3://02a9/song.mp3 copy: s3://02a8/cp_noguess.mp3 to s3://02a9/cp_noguess.mp3 copy: s3://02a8/text_plain.mp3 to s3://02a9/text_plain.mp3 copy: s3://02a8/copied_noguess.mp3 to s3://02a9/copied_noguess.mp3 copy: s3://02a8/cp_text_html.mp3 to s3://02a9/cp_text_html.mp3 copy: s3://02a8/noguess.mp3 to s3://02a9/noguess.mp3 $ aws s3api head-object --bucket 02a9 --key song.mp3 { "LastModified": "Tue, 13 May 2014 15:55:30 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" } $ aws s3api head-object --bucket 02a9 --key text_plain.mp3 { "LastModified": "Tue, 13 May 2014 15:55:30 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "text/plain", "ContentLength": "0" }
というように、コピー元の ContentType がそのまま引き継がれている。
aws s3api put-object の場合
次に aws s3 cp
コマンドのローレベル API である aws s3api put-object を触ってみる。
ローカルのファイルシステムにあるオブジェクトをコピーするためにつかう。
S3 の Put Object API の aws cli 対応版
デフォルト
$ aws s3api put-object --bucket 02a8 --key song.mp3 --body song.mp3 { "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } $ aws s3api head-object --bucket 02a8 --key song.mp3 { "LastModified": "Tue, 13 May 2014 16:02:17 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "binary/octet-stream", "ContentLength": "0" }
デフォルトでは ContentType は guess されない。
ContentType を指定
--content-type
をつけて ContentType を指定する。
$ aws s3api put-object --body song.mp3 --bucket 02a8 --key audio_mpeg.mp3 --content-type audio/mpeg { "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } $ aws s3api head-object --bucket 02a8 --key audio_mpeg.mp3 { "LastModified": "Tue, 13 May 2014 16:03:35 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" }
copy-object の場合
次に aws s3 cp
コマンドのもう一つのローレベル API である aws s3api copy-object を触ってみる。
S3 にあるオブジェクトをコピーするためにつかう。
S3 の Put Object – Copy API の aws cli 対応版
<pre>$ aws s3api head-object --bucket 02a8 --key audio_mpeg.mp3 { "LastModified": "Tue, 13 May 2014 16:23:13 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" } $ aws s3api copy-object --copy-source 02a8/audio_mpeg.mp3 --bucket 02a8 --key copied_audio_mpeg.mp3 { "CopyObjectResult": { "LastModified": "2014-05-13T16:36:57.000Z", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } } $ aws s3api head-object --bucket 02a8 --key copied_audio_mpeg.mp3 { "LastModified": "Tue, 13 May 2014 16:36:57 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" }
デフォルトでは、コピー元の ContentType が引き継がれる。
ContentType を指定
--content-type
をつけて ContentType を指定してみる。
$ aws s3api copy-object --copy-source 02a8/song.mp3 --bucket 02a8 --key copied_text_html.mp3 --content-type text/html { "CopyObjectResult": { "LastModified": "2014-05-13T16:06:01.000Z", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } } $ aws s3api head-object --bucket 02a8 --key copied_text_html.mp3 { "LastModified": "Tue, 13 May 2014 16:06:01 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "binary/octet-stream", "ContentLength": "0" }
なぜか ContentType が “text/html” に変わっていない。
原因は、コピー元が S3 オブジェクトの場合、 --metadata-directive
を REPLACE にしないとコピー元のメタデータが引き継がれるため。(デフォルトのモードは COPY でメタデータが引き継がれる
)
詳細は PUT Object – Copy API の x-amz-metadata-directive ディレクティブの説明を参照
--metadata-directive REPLACE
をつけて ContentType を指定してみる。
$ aws s3api copy-object --copy-source 02a8/song.mp3 --bucket 02a8 --key copied_metadata_replace.mp3 --content-type text/html --metadata-directive REPLACE { "CopyObjectResult": { "LastModified": "2014-05-13T16:07:14.000Z", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } } $ aws s3api head-object --bucket 02a8 --key copied_metadata_replace.mp3 { "LastModified": "Tue, 13 May 2014 16:07:14 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "text/html", "ContentLength": "0" }
期待どおり ContentType が変わった。
S3 オブジェクトの ContentType だけを更新する
最終目標にやりたかったのがこれ。
初期データの投入方法がまずくて、ContentType を付け直したいときにどうすればよいのか?
残念なことに AWS S3 の RestAPI にはそんな都合のよい API は存在しない。
自分自身にコピーして、ContentType を上書きすれば OK
“ContentType”: “binary/octet-stream” な s3://02a8/song.mp3 の ContentType を “audio/mpeg” に変えてみる。
$ aws s3api head-object --bucket 02a8 --key song.mp3 { "LastModified": "Tue, 13 May 2014 16:02:17 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "binary/octet-stream", "ContentLength": "0" } $ aws s3api copy-object --bucket 02a8 --copy-source 02a8/song.mp3 --key song.mp3 --content-type audio/mpeg --metadata-directive REPLACE { "CopyObjectResult": { "LastModified": "2014-05-13T16:08:54.000Z", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"" } } $ aws s3api head-object --bucket 02a8 --key song.mp3 { "LastModified": "Tue, 13 May 2014 16:08:54 GMT", "AcceptRanges": "bytes", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "ContentType": "audio/mpeg", "ContentLength": "0" }
ということで無事更新出来た。
めでたし、めでたし。
One thought on “AWS CLIでS3オブジェクトのContentTypeを設定する”