cloudflareのR2というストレージサービスがあるみたいなので調査と使ってみる
色々とまずは見てみる
とりあえずこれを見て進める
- アカウントを作る
- クレジットを登録
- バケットを登録する
で確認ができた。
画像もアップロードをしたがデフォルトでは非公開になるっぽい
バケットをデフォルトで公開にするにはカスタムドメインをcloudflareのDNSに登録をする必要があるっぽい。
とりあえずcloudflareで適当なドメインを買って、バケットに紐づけて購入をしたドメインを登録をしてみた。
まずはバケットを登録する
パブリックアクセスのカスタムドメインを登録する。
バケットごとに別のドメインを登録しておかないとエラーが出るのでサブドメインを適当に指定をして別のドメインで登録をする。
数分経つとアクティブになる。
カスタムドメインが表示をされてこれでアクセスができるようになる。
ファイルをアップロードできるようにする(サーバーでアップロード)
やることは
api tokenを発行する。
必要に応じて厳しくする等の対応が必要かと思うのですが、特段問題がなければ下記のような設定で良いと思います。
fileのデータをサーバー側に送り、S3Client
でs3のインスタンスを作り、PutObjectCommandで画像をアップロードする。
詳細は下記をご確認ください。
署名付きURLを発行してブラウザでアップロードできるようにする
こちらのcreatePresignedUrlWithClient
を使ってアップロードをする。
かなり雑に書いています。zod等を使ってparseして型付けをするなり、エラー処理をちゃんとやる等が必要そうです。
'use client'
import { format } from 'date-fns'
import { useState } from 'react'
export default function Home() {
const [uploading, setUploading] = useState(false)
const [url, setUrl] = useState('')
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (!file) return
setUploading(true)
const fileName = `${format(new Date(), 'yyyyMMddHHmm')}_${file.name}`
const res = await fetch('/api/presigned-url', {
method: 'POST',
body: JSON.stringify({ fileName }),
headers: {
'Content-Type': 'application/json',
},
})
if (res.ok) {
const { data, message } = await res.json()
const result = await fetch(data.presignedUrl, {
method: 'PUT',
headers: {
'Content-Type': file.type,
},
body: file,
})
if (result.ok) {
alert(message)
// https://avatar.storage-url.com の部分はcloudflareで登録をしたカスタムドメインの部分
setUrl(`https://avatar.storage-url.com/${fileName}`)
}
} else {
setUrl('')
alert('アップロードに失敗しました。')
}
setUploading(false)
}
return (
<div>
<div>
urlは{url}
{url && !uploading ? (
<>
<h2>アップロードされた画像</h2>
<div>
<img src={url} alt="upload" width={200} />
</div>
</>
) : (
<>
<h2>画像をアップロード</h2>
<input type="file" onChange={handleFileChange} className="hidden" id="upload" />
<label htmlFor="upload">upload</label>
</>
)}
</div>
</div>
)
}
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
import { type NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) {
const reqData = await req.json()
const fileName = reqData.fileName
const presignedUrl = await createPresignedUrlWithClient({
bucket: 'avatar', // cloudflareで事前に登録をしているバケット名
key: fileName,
})
return NextResponse.json({
message: 'アップロードに成功しました。',
data: { presignedUrl },
})
}
const createPresignedUrlWithClient = ({ bucket, key }: { bucket: string; key: string }) => {
const client = new S3Client({
region: 'auto',
endpoint: process.env.R2_ENDPOINT as string,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY as string,
secretAccessKey: process.env.R2_SECRET_KEY as string,
},
})
const command = new PutObjectCommand({ Bucket: bucket, Key: key })
return getSignedUrl(client, command, { expiresIn: 3600 })
}
料金的に安いみたい
ここをみると、どのくらいの金額になるのかを計算できる。
https://r2-calculator.cloudflare.com/?_gl=1eoavyw_gcl_auMTE0Njg3NDY2OS4xNzI1MzY1NDYz_gaYTk0YTIxNWItNmY1ZC00ZmExLWFhY2UtNjhiMDE2Y2U4OGFj_ga_SQCRB0TXZW*MTcyNzU2NzA4MS4xMC4wLjE3Mjc1NjcwODIuNTkuMC4w