😺

AWS S3で署名付きURLを使った画像のアップロードを試してみる

に公開

こんにちは!TRUSTART株式会社のgoaです!

直近の業務で画像のアップロード機能を実装する機会があり、フロントエンドからmultipart/form-dataでバックエンドサーバーに送信し、サーバーからS3にアップロードする方法をとったのですが「引き出しを増やしたい」と感じました。

AWS S3などのクラウドストレージサービスには、サーバーを介さずにフロントエンドから直接アップロードできる仕組み(署名付きURL)があり、バックエンドサーバーでのファイルの受信・転送処理の負荷を軽減できるというメリットがあることを知りました。

そこで今回は、S3の署名付きURLを使った画像アップロードを最小構成で試してみたいと思います。

今回試す構成

署名付きURLでのアップロードの実践が目的なので、認証などは省き、AWSも最小構成で試していきます。

  • フロントエンド: React
  • バックエンド: Lambda (Python) + API Gateway(HTTP API)
  • ストレージ: S3

処理の流れ

  1. フロントエンドから「署名付きURL」の発行をリクエスト
  2. バックエンドのLambdaで「署名付きURL」を発行し、フロントエンドへ返却
  3. フロントエンドで受け取った「署名付きURL」を使って、S3へ画像をアップロード

フロントエンドの実装

署名付きURLの発行をリクエストし、受け取った署名付きURLを使ってS3にアップロードします。
リクエストとアップロード部分を抜粋すると以下のように実装しました。

const uploadFile = async (file) => {
  // Lambdaに署名付きURLの発行をリクエスト
  const res = await fetch(BACKEND_URL, {
    method: 'POST',
    body: JSON.stringify({
      filename: file.name,
      contentType: file.type
    })
  });
  const { presignedUrl } = await res.json();

  // 受け取った「署名付きURL」を使って、S3へ画像をアップロード
  await fetch(presignedUrl, {
    method: 'PUT',
    headers: { 'Content-Type': file.type },
    body: file
  });
};

バックエンドの実装

フロントエンドからのリクエストを受けて、署名付きURLを発行しています。
※API GatewayのCORS設定、LambdaへのS3アクセス権限の付与は別途行っています。ここでは詳細は省略します

import json
import boto3

s3 = boto3.client('s3')
BUCKET_NAME = 'bucket-name'

def lambda_handler(event, context):
    body = json.loads(event['body'])
    filename = body['filename']
    content_type = body['contentType']

    s3_key = f"uploads/{filename}"

    # 署名付きURLを発行
    presigned_url = s3.generate_presigned_url(
        'put_object',
        Params={
            'Bucket': BUCKET_NAME,
            'Key': s3_key,
            'ContentType': content_type
        },
        ExpiresIn=300 # 有効期限の設定
    )

    return {
        'statusCode': 200,
        'body': json.dumps({
            'presignedUrl': presigned_url
        })
    }

S3のCORS設定

フロントエンドからS3へアップロードするために、S3にCORS設定を行います。
今回試したローカル環境からアップロードする場合の設定例を記述しています。

[
    {
        "AllowedHeaders": ["*"],
        "AllowedMethods": ["PUT"],
        "AllowedOrigins": ["http://localhost:5173"],
        "ExposeHeaders": []
    }
]

動作確認

S3へアップロードされていることが確認できました。

おわりに

今回は、ファイルアップロードの引き出しを増やすために、AWS S3を使った署名付きURLのファイルアップロードの実装を試してみました。思っていたよりもシンプルに実装できたと感じています。
S3キーをDBに保存して、署名付きURLを使った画像の取得まで試したかったのですが、次の機会としたいと思います。
また、今回は画像単体のアップロードでしたが「記事に紐づく画像」のように、他のデータとのリレーションをどう実現するかも試していきたいです。


TRUSTART株式会社は、一緒に働くメンバーを募集しています!
インターンメンバーも大募集中です!
興味を持っていただいた方は、ぜひ弊社のページをご確認ください!!!

https://www.trustart.co.jp/recruit/

TRUSTARTテックブログ

Discussion