0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

S3イベントのkeyは`unquote_plus`しないと日本語ファイル名が壊れる

0
Posted at

背景

S3へのファイルアップロードをトリガーにLambdaを起動する構成をAWS SAMで構築しました。日本語ファイル名やフォルダ付きキーを扱う際に必要な処理を整理します。

1. Type: S3イベントの最小構成

Resources:
  UploadBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-upload-${AWS::AccountId}"
    DeletionPolicy: Delete

  S3EventFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: app.lambda_handler
      Events:
        S3Event:
          Type: S3
          Properties:
            Bucket: !Ref UploadBucket
            Events: s3:ObjectCreated:*

Type: S3の1行で、S3側のイベント通知設定と、Lambda側の「S3からの呼び出しを許可するリソースベースポリシー」の両方が自動作成されます。

2. バケット名は!Sub "...-${AWS::AccountId}"でグローバルユニーク化

S3バケット名はAWS全体(全リージョン・全アカウント)で一意である必要があります。

BucketName: !Sub "${AWS::StackName}-upload-${AWS::AccountId}"

スタック名だけでは他アカウントと衝突する可能性があるため、アカウントIDを含めるのが確実な方法です。一度使われたバケット名は削除後もしばらく再利用できないことがあるため、この命名規則は覚えておいて損はありません。

3. urllib.parse.unquote_plusが必須な理由

import urllib.parse

def lambda_handler(event, context):
    for record in event["Records"]:
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])

S3のキー名に日本語やスペース、特殊文字が含まれると、Lambdaに渡されるeventの中ではURLエンコードされた状態になります。

アップロードしたファイル名 デコード前 デコード後
テスト.txt %E3%83%86%E3%82%B9%E3%83%88.txt テスト.txt
my file.txt my+file.txt my file.txt

unquote_plusを使わないと、ログや後続処理で%E3%83%86...のような文字列がそのまま流れてしまいます。unquoteではなくunquote_plusを使うのは、スペースが+に変換されるケース(my+file.txt)にも対応するためです。

4. event["Records"]は複数件になり得る

for record in event["Records"]:
    bucket = record["s3"]["bucket"]["name"]
    key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])

通常は1件ですが、複数ファイルの同時アップロード(マルチパートアップロードの完了通知など)ではRecordsが複数件になる場合があります。forループを前提にした実装にしておくのが安全です。

5. DeletionPolicy: Deleteでも空にしないと削除できない

UploadBucket:
  Type: AWS::S3::Bucket
  DeletionPolicy: Delete

DeletionPolicy: Deleteを指定していても、オブジェクトが1件でも残っているバケットはCloudFormationから削除できません。

aws s3 rm s3://バケット名 --recursive --region ap-northeast-1  # 先に空にする
sam delete --stack-name スタック名 --region ap-northeast-1

これを忘れるとsam deleteが以下のエラーで失敗します。

Error: Failed to delete the stack: ...
The following resource(s) failed to delete: [UploadBucket]

まとめ

unquote_plusによるURLデコードと、削除前のバケット空化、この2点がS3イベントLambdaの実装・運用で押さえておくべきポイントでした。フォルダ付きキーや複数ファイル同時アップロードの検証手順は元記事にまとめています。

→ S3ファイルアップロードトリガーでLambdaを自動起動するハンズオン(ブログ)

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?