일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- GIT
- react native picker
- react native font
- 리액트 네이티브 에러
- img upload
- Access Key 생성
- PongWorld
- 리액트
- babel.config.js
- 문자열 대소문자 구별
- AWS
- Project
- aws bucket 정책
- react native 개발
- 리액트 네이티브
- s3 upload
- firebase 라이브러리
- 에러
- react native 세팅
- error
- fire base
- React
- 리엑트 네이티브 아이콘
- react native CLI
- 백준
- 문자열 대소문자
- react native
- Next.js
- js
- AWS Access Key
- Today
- Total
밝을희 클태
[ Next.JS ] AWS S3에 이미지(image)를 업로드, 미리보기 본문
환경
Next.js 14 APP Router
AWS SDK for Javascript v3
https://gaebarsaebal.tistory.com/79
S3 bucket 설정은 이 전 포스팅에서 다룬다.
나는 S3 이미지 업로드를 서버에서 할 것이다. 클라이언트에서 할 수도 있지만 클라이언트에서 하면 AWS key가 노출될 위험이 있고 Presigned URL을 사용해 key의 노출을 막을 수 있지만 더 많은 작업을 해줘야 해서 서버에서 바로 업로드하려고 한다.
일단 API endpoint를 만들자
# /root/.env.local
AWS_ACCESS_KEY_ID=IAM(보안 자격 증명) user에서 발급받은 access key
AWS_SECRET_ACCESS_KEY=IAM(보안 자격 증명) user에서 발급받은 secret access key
AWS_REGION=S3 bucket 국가 ex) ap-northeast-2
S3_BUCKET_NAME=bucket name
$ npm install @aws-sdk/client-s3
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { NextResponse } from 'next/server';
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
});
export async function POST(req) {
try {
const formData = await req.formData();
const files = formData.getAll('files');
const uploadPromises = [];
const uploadedUrls = [];
for (const file of files) {
// 각 파일에 대해 루프를 시작 files는 formData.getAll('files')를 통해 가져온 파일 리스트
const arrayBuffer = await file.arrayBuffer();
// 파일을 ArrayBuffer로 변환 ArrayBuffer는 바이너리 데이터를 저장할 수 있는 일반적인 버퍼
const buffer = Buffer.from(arrayBuffer);
// ArrayBuffer를 Node.js Buffer 객체로 변환, Node.js Buffer 객체는 S3에 업로드할 수 있는 형태의 데이터
const uploadParams = {
Bucket: process.env.S3_BUCKET_NAME,
// 업로드할 S3 버킷의 이름. 환경 변수로 설정된 값을 사용
Key: `${Date.now()}_${file.name}`,
// S3에 저장될 객체의 키(파일 이름) 여기서는 파일 이름 앞에 현재 타임스탬프를 붙여서 고유한 파일 이름을 생성
Body: buffer,
// 업로드할 파일의 내용 Buffer 객체를 사용
ContentType: file.type,
// 클라이언트에서 업로드된 파일의 타입을 그대로 사용
};
const command = new PutObjectCommand(uploadParams);
// S3에 파일을 업로드하는 명령을 생성
const uploadPromise = s3Client.send(command)
.then(() => {
const url = `https://${process.env.S3_BUCKET_NAME}.s3.${process.env.AWS_REGION}.amazonaws.com/${uploadParams.Key}`;
// 파일이 성공적으로 업로드된 후 해당 파일의 URL을 생성
// S3 버킷의 URL 형식을 사용 'https://{버킷 이름}.s3.{리전}.amazonaws.com/{파일 키}'
uploadedUrls.push(url);
// 생성된 URL을 uploadedUrls 배열에 추가
})
.catch(error => {
console.error(`Error uploading file ${file.name}:`, error);
});
uploadPromises.push(uploadPromise);
// 각 업로드 작업을 Promise 배열에 추가
}
await Promise.all(uploadPromises);
return NextResponse.json({ uploadedUrls }, { status: 200 });
} catch (error) {
return NextResponse.json({ error: '업로드중 문제 발생' }, { status: 500 });
}
}
그다음 클라이언트 코드로 와서 이미지를 선택해서 담을 Hook을 만들어준다.
imageUrls는 사용자가 선택한 이미지를 미리 보기 위해 사용되고
imageFiles는 AWS S3에 업로드하기 위해 사용된다.
const [uploadImages, setUploadImages] = useState({
imageFiles: [],
imageUrls: [],
});
그리고 Input을 만들어서 image만 선택할 수 있게 해 주고 이미지 선택을 완료했을 때 handleImageUpload 함수를 실행시켜 준다.
URL.createObjectURL(file)는 각 파일 객체에 대해 브라우저가 해당 파일을 참조할 수 있는 임시 URL을 생성한다.
이제 이미지를 사용자에게 미리 보여주고 싶으면 imageUrls를 src에 주면 된다.
const handleImageUpload = useCallback(
e => {
if (!e.target.files) return;
const files = e.target.files;
const filesArray = Array.from(files);
const newArray = filesArray.map(file => URL.createObjectURL(file));
setUploadImages({
imageFiles: [...uploadImages.imageFiles, ...filesArray],
imageUrls: [...uploadImages.imageUrls, ...newArray],
});
},
[uploadImages],
);
<input type="file" multiple accept="image/*" onChange={handleImageUpload} id="images" hidden />
이제 이미지를 처음에 만든 API endpoint로 formdata를 보내서 서버에서 업로드를 해준다.
이미지 업로드에 성공했으면 S3 bucket에 올라간 이미지 URL들이 반환될 거고
실패했으면 error mag를 반환할 것이다.
const handleUpload = async () => {
const formData = new FormData();
uploadImages.imageFiles.forEach(file => {
formData.append('files', file);
});
try {
const res = await fetch('/api/upload/product', {
method: 'POST',
body: formData,
});
const data = await res.json();
if (res.ok) {
...
} else {
...
}
} catch (error) {
...
}
};
이미지 업로드에 성공하면 bucket에 이렇게 객체들이 생성이 돼있다.
'NextJS' 카테고리의 다른 글
[ Next.JS ] Input 태그에서 HEIC 확장자를 jpeg로 변환하기 (0) | 2024.06.15 |
---|---|
[ Next.js] Image태그의 sizes (1) | 2024.06.12 |
[NextJS] 스크롤 애니메이션 구현하기 IntersectionObserver API (1) | 2023.12.03 |