今回は、サーバレス(AWS Lambda(Python 3.8) + S3)でファイルをアップロードする仕組みが必要となったため、その時に調べた方法の備忘録です。
Spring boot(EC2+RDS)でWebアプリケーションとして作成する予定だったのですが、コスト面で見直した結果、今回のような構成で行くことにしました。 LambdaやAPI Gatewayは初めて使っみてたのですが、当初思っていたよりは簡単に利用できて驚きました。 今回アクセスコントロール周りには触れていないのであしからず...
Lambda関数の作成
まずはLambda関数を作成します。 コンソールでLambdaを選択し、関数の作成から新しいLambda関数を作成します。 冒頭の通り、今回はPython 3.8をランタイムに選択します。 関数の内容は以下の通りです。
import json import boto3 import base64 import io from datetime import datetime import cgi BUCKET_NAME='xxxx-test-backet-1' DIRECTORY='uploaded_files/' s3 = boto3.resource('s3') def lambda_handler(event, context): bucket = s3.Bucket(BUCKET_NAME) body = base64.b64decode(event['body-json']) fp = io.BytesIO(body) environ = {'REQUEST_METHOD': 'POST'} headers = { 'content-type': event['params']['header']['content-type'], 'content-length': len(body) } fs = cgi.FieldStorage(fp=fp, environ=environ, headers=headers) for f in fs.list: print("filename=" + f.filename) bucket.put_object(Body=f.value, Key=DIRECTORY+f.filename) return { 'statusCode': 200, 'body': json.dumps('アップロード完了') }
multipart/form-dataで複数ファイルをアップロードできるようにしておきます。
ただし、Lambdaのペイロードサイズ上限は6MBとなっているため、事前に要件の確認が必要です。
アップロードされたファイルの読み込みには、cgiモジュールのFieldStorageを利用することにします。
保存先はS3で、Bucket内に'uploaded_files'というフォルダを作ってそこに保存します。
multipart/form-dataで複数アップロードしたいので、保存もファイルごとに行います。
S3への保存は、AWS SDK for Python (Boto3)をimportして利用します。
API Gatewayでインタフェースを作成
トリガーの追加から、API Gatewayを選択します。
API Gatewayのコンソール画面でリソースを設定します。今回はmultipart/form-dataでファイルを送信する為に、アクション→メソッドの作成→POSTを選択してPOSTメソッドを受け付けるようにします。
統合リクエストにはLambdaを指定しておきます。
ファイルをアップロードする
Chrome拡張のTalend API Testerを使用してファイルをアップロードします。
今回は試しにエクセルファイルを2つアップロードしてみます。
すでにアップロード済みのファイルと同じファイル名でアップロードすると上書き保存となります。
以下のようなHTMLをS3上に用意してしまえば、一つのアプリケーションの出来上がりです。
<!doctype html> <html> <head> <meta charset="utf-8"/> </head> <body> <form method="post" action="https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/default/fileUploader" enctype="multipart/form-data"> <p>ファイル:<br> <input type="file" name="file1" size="30"><br> <input type="file" name="file2" size="30"></p> <p><input type="submit" value="送信する"></p> </form> </body> </html>
今回は以上です。
参考リンク
[Python] POSTされたmultipart/form-dataをFieldStorageでパースする - Qiita