困っていたこと
s3にアップロードした画像のURLを参照したときに、lamda関数(リサイズを行う)の処理が追いつかず未解決で403が返ってくる。
(オンメモリのプレビュー画像では要件を満たせない場合)
前提
s3にアップロードした画像に対して、リサイズ等のlamda関数を実行して最適化した画像を生成し、専用バケットに再登録するという処理を行っている場合に発生する事例。
解決策
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で行うのが簡単とのお声も頂きました。
勉強になります🙏