[Next.js] AWS S3 이미지 업로드 예제 (1) 글에서 소스 수정
전체 소스
https://github.com/kimfame/next-s3/tree/825116b3274bc549f67e3661e54bde836f725a34
패키지 설치
yarn add @aws-sdk/s3-request-presigner
S3 이미지 업로드 API에서 코드 추가
/src/app/api/upload/route.js
import {
GetObjectCommand,
PutObjectCommand,
S3Client,
} from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
import { NextResponse } from 'next/server'
import { v4 as uuidv4 } from 'uuid'
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
})
async function uploadFileToS3(file, fileName, fileType) {
const key = fileName
const body = file
const contentType = fileType
const parmas = {
Bucket: process.env.AWS_S3_BUCKET_NAME,
Key: key,
ACL: 'public-read',
ContentType: contentType,
Body: body,
}
const command = new PutObjectCommand(parmas)
await s3Client.send(command)
}
// 추가된 함수
async function getImageUrl(fileName) {
const command = new GetObjectCommand({
Bucket: process.env.AWS_S3_BUCKET_NAME,
Key: fileName,
})
// 서명된 URL은 60초만 접근 가능
const url = await getSignedUrl(s3Client, command, { expiresIn: 60 })
return url
}
export async function POST(req) {
try {
const formData = await req.formData()
const file = formData.get('file')
if (!file) {
return NextResponse.json({ error: 'File is required.' }, { status: 400 })
}
const fileExtension = file.name.split('.').slice(-1)[0]
const newFileName = `${uuidv4()}.${fileExtension}`
const fileType = file.type
const buffer = Buffer.from(await file.arrayBuffer())
await uploadFileToS3(buffer, newFileName, fileType)
// imageUrl 생성 방식 변경
// const imageUrl = `${process.env.AWS_S3_OBJECT_URL}/${newFileName}`
const imageUrl = await getImageUrl(newFileName)
return NextResponse.json(imageUrl)
} catch (error) {
return NextResponse.json({ error })
}
}
- 이전 소스에서 새로 추가 및 변경된 부분은 getImageUrl 함수 추가와 imageUrl 변수 할당하는 값 변경
- getSignedUrl 파라미터 중 expiresIn의 단위는 '초'이다. 3600으로 설정하면 1시간 동안 이미지 URL 접근 가능
이미지 업로드폼에서 URL 주소 표기
/src/components/UploadForm.jsx
'use client'
import Image from 'next/image'
import { useState } from 'react'
export default function Home() {
const [file, setFile] = useState(null)
const [uploading, setUploading] = useState(false)
const [imageUrl, setImageUrl] = useState('')
function handleFileChange(event) {
setFile(event.target.files[0])
}
async function handleSubmit(event) {
event.preventDefault()
if (!file) return
setUploading(true)
const formData = new FormData()
formData.append('file', file)
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
})
const data = await response.json()
setImageUrl(data)
setUploading(false)
} catch (error) {
setUploading(false)
}
}
return (
<>
<h1>Upload Images to AWS S3</h1>
<form onSubmit={handleSubmit}>
<input type="file" accept="image/*" onChange={handleFileChange} />
<button type="submit" disabled={!file || uploading}>
{uploading ? 'Uploading...' : 'Upload'}
</button>
</form>
<p>{imageUrl}</p>
{imageUrl && (
<Image src={imageUrl} width="300" height="300" alt="Image" />
)}
{!imageUrl && <h2>No image</h2>}
</>
)
}
- 이전과 동일한 코드이나 <p>{imageUrl}</p>만 추가
미리 서명된 URL을 가지고 주소창에 넣어서 접근 가능한지 테스트하기 위함 (반드시 필요한 작업은 아님)
[출처]
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-s3-request-presigner/
https://medium.com/@antoinewg/upload-a-file-to-s3-with-next-js-13-4-and-app-router-e04930601cd6
https://conermurphy.com/blog/presigned-urls-nextjs-s3-upload
'React > Next.js' 카테고리의 다른 글
[Next.js] NextAuth Google Login 추가 (1) | 2024.03.30 |
---|---|
[Next.js] AWS S3 ACL Private 특정 유저만 접근 허용 (0) | 2024.03.28 |
[Next.js] AWS S3 이미지 업로드 예제 (1) (0) | 2024.03.22 |
[Next.js] 아이디, 비밀번호 로그인 예제 (0) | 2024.03.18 |
[Next.js] 프로젝트 생성 / 개발 서버 실행 (0) | 2024.03.11 |