[s3-example] 5. S3 이미지 업로드

Project
2023-09-15

image

  1. [파일 업로드] 눌러서 파일 선택한다.
<label htmlFor="file">파일 업로드</label> <input id="file" onChange={handleFileChange} />
<label htmlFor="file">파일 업로드</label> <input id="file" onChange={handleFileChange} />
  1. 선택한 파일을 formData에 추가하고, body에 formData 담아 서버에 POST 요청한다.
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => { if (!e.target.files) return; const formData = new FormData(); // key가 file0, file1, ...인 form 필드의 value에 파일 정보를 담아 formData에 추가한다. // 서버에서 파일을 구별하기 위해 key를 이런 식으로 설정한다. for (let i = 0; i < e.target.files.length; i++) { formData.append(`file${i}`, e.target.files[i]); } // POST 요청 postImages(formData); };
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => { if (!e.target.files) return; const formData = new FormData(); // key가 file0, file1, ...인 form 필드의 value에 파일 정보를 담아 formData에 추가한다. // 서버에서 파일을 구별하기 위해 key를 이런 식으로 설정한다. for (let i = 0; i < e.target.files.length; i++) { formData.append(`file${i}`, e.target.files[i]); } // POST 요청 postImages(formData); };
// 인수로 받은 formData를 body에 담아 POST 요청한다. const postImages = async (formData: FormData) => { await fetch("http://localhost:4000/image", { method: "POST", body: formData, }); };
// 인수로 받은 formData를 body에 담아 POST 요청한다. const postImages = async (formData: FormData) => { await fetch("http://localhost:4000/image", { method: "POST", body: formData, }); };
  1. 클라이언트로부터 받아온 formData 파싱하기
const fileData = await new Promise((resolve, reject) => { const form = new formidable.IncomingForm(); // formidable로 폼 파싱 form.parse(req, (err, fields, files) => { if (err) return reject(err); return resolve({ fields, files }); }); }); const parsedFileData = fileData;
const fileData = await new Promise((resolve, reject) => { const form = new formidable.IncomingForm(); // formidable로 폼 파싱 form.parse(req, (err, fields, files) => { if (err) return reject(err); return resolve({ fields, files }); }); }); const parsedFileData = fileData;
// parsedFileData { fields: {}, files: { file0: [ [PersistentFile] ], file1: [ [PersistentFile] ] } }
// parsedFileData { fields: {}, files: { file0: [ [PersistentFile] ], file1: [ [PersistentFile] ] } }
  1. parsedFileData.files의 파일들을 fs.createReadStream() 함수로 WriteStream 객체로 만들고 업로드하기
Object.values(parsedFileData.files).forEach(async item => { // fs.createReadStream이용해 스트림 전환 후 올리기 const fileBuffer = fs.createReadStream(item[0].filepath); fileBuffer.on('error', err => console.log(err)); const fileName = item[0].originalFilename; await uploadFile(fileBuffer, fileName, item[0].mimetype); });
Object.values(parsedFileData.files).forEach(async item => { // fs.createReadStream이용해 스트림 전환 후 올리기 const fileBuffer = fs.createReadStream(item[0].filepath); fileBuffer.on('error', err => console.log(err)); const fileName = item[0].originalFilename; await uploadFile(fileBuffer, fileName, item[0].mimetype); });
async function uploadFile(fileBuffer, fileName, mimetype) { const uploadParams = { Bucket: awsS3Bucket, Key: fileName, Body: fileBuffer, ContentType: mimetype, }; const res = await s3.send(new PutObjectCommand(uploadParams)); return res.$metadata.httpStatusCode; }
async function uploadFile(fileBuffer, fileName, mimetype) { const uploadParams = { Bucket: awsS3Bucket, Key: fileName, Body: fileBuffer, ContentType: mimetype, }; const res = await s3.send(new PutObjectCommand(uploadParams)); return res.$metadata.httpStatusCode; }
  1. 이미지 다시 불러오기(revalidate)
const [images, setImages] = useState<string[]>(); const fetchDataAndSetState = () => { getImages().then(res => setImages(res)); }; ... return ( <label htmlFor="file">파일 업로드</label> <input id="file" onChange={e => { handleFileChange(e).then(() => setTimeout(() => fetchDataAndSetState(), 500)); }} multiple type="file" /> ... )
const [images, setImages] = useState<string[]>(); const fetchDataAndSetState = () => { getImages().then(res => setImages(res)); }; ... return ( <label htmlFor="file">파일 업로드</label> <input id="file" onChange={e => { handleFileChange(e).then(() => setTimeout(() => fetchDataAndSetState(), 500)); }} multiple type="file" /> ... )

파일 업로드 후 즉시 S3에 객체의 업로드가 반영이 안되기 때문에 setTimeout 함수로 시간 설정 후 fetchDataAndSetState 함수 호출한다.

관련 포스트

post thumbnail

[react-auth-example] 2. 프론트엔드

로컬 스토리지, 세션 스토리지, 쿠키의 차이점을 알기 쉽게 페이지 및 API를 따로 구현했다. 프론트엔드에서 fetch 요청 시 옵션으로 credentials: "include"를

2023-08-08
post thumbnail

[react-auth-example] 1. 백엔드

해시된 password를 사용하지 않았다. 로그인을 하면 jwt.sign()을 이용하여 토큰을 발급한다. - 웹 스토리지 : JWT를 브라우저에 전달한다. - 쿠키 : 서버에서 쿠

2023-08-08
post thumbnail

[s3-example] 4. S3 이미지 불러오기

퍼블릭화한 S3 버킷의 객체 URL은 https://[버킷명].s3.[버킷리전].awazonaws.com/[객체]로 되어있다. ex) https://doromo-example.s3

2023-07-27
post thumbnail

[s3-example] 3. 백엔드 구축

Node.js와 express로 백엔드를 구축했다. 백엔드에서 aws-sdk를 이용하여 버킷과 객체에 접근할 것이다. MY_AWS_ACCESS_KEY : IAM 설정에서 발급받은

2023-07-27

도로모의 기술 블로그

# Contact : jyw966@naver.com

Copyright © doromo. All Rights Reserved.