search
LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

s3バケットの画像の解決をポーリングする

困っていたこと

s3にアップロードした画像のURLを参照したときに、lamda関数(リサイズを行う)の処理が追いつかず未解決で403が返ってくる。
(オンメモリのプレビュー画像では要件を満たせない場合)

前提

s3にアップロードした画像に対して、リサイズ等のlamda関数を実行して最適化した画像を生成し、専用バケットに再登録するという処理を行っている場合に発生する事例。

s3_upload&resize.jpg

解決策

fetch APIで画像のURLを叩いてstatusCode: 200が返ってくるまでPollingする。

import axios from 'axios'
import * as api from '@/api'

type Form = {
  Content-Type: string
  Policy: string
  X-Amz-Algorithm: string
  X-Amz-Credential: string
  X-Amz-Date: string
  X-Amz-Signature: string
  key: string
  x-amz-server-side-encryption: string
}

const checkS3Resolve = async (url: string) => {
  const res = await fetch(url)
  // 成功したら200を返す
  return res.status
}

export const upload = async (
  host_url: string,
  url: string,
  file: File,
  form: Form,
) => {
  const formData = new FormData()
  for (const key in form) {
    const value = form[key]
    if (value !== undefined) {
      formData.append(key, value)
    }
  }
  // fileは最後にappendしないとエラー
  formData.append('file', file)
  await axios.post(url, formData, { timeout: 10000 })

  const hostUrl = `https://s3-ap-northeast-1.amazonaws.com/hoge/origin`

  const delay = (ms: number) => new Promise(res => setTimeout(res, ms))
  let result = 404
  // S3で画像が処理されるまで待つ
  while (result !== 200) {
    // 1.5秒ごとにS3側の状態確認処理を実施
    await delay(1500)
    result = await checkS3Resolve(hostUrl)
  }
  ...
}

最後に

かなりエッジケースにはなりますが、個人的にちょっと詰まったので記載しました。
他にもいい方法などございましたらコメントお待ちしております。

AWS周りのアーキテクチャについては画像元データはs3に格納して、リサイズの処理についてはlamdaを直接叩いてしまう方が良さそうとのコメントを頂きました。
(その方がエラーハンドリング等も考えると良さそう)
また、小規模の案件なら画像の管理はFirebase Resize Imagesで行うのが簡単とのお声も頂きました。

勉強になります🙏

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
What you can do with signing up
0