일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 배포
- 신상마켓
- 정리
- vsCode
- 로그인
- vue login
- plugin
- vue
- 플러그인
- react-query
- 회고록
- javascript
- react
- nginx
- express
- jwt
- Firebase
- login
- Docker
- Git
- vuex
- 토이프로젝트
- 기획
- AWS
- 프론트
- 뷰
- extension
- 셋팅
- database
- PWA
- Today
- Total
강디너의 개발 일지
이미지 업로드 - 프론트 부터 AWS S3 까지의 과정 본문
사용자가 이미지를 선택할 때부터 백엔드 API, AWS S3로 들어가는 과정입니다.
토이 프로젝트에서 진행중인, 리뷰 등록하는 것을 보여드리면서 설명하겠습니다.
기술 스텍: Vue.js, Node.js, AWS S3, MYSQL
보통 파일 선택하는 input type=file 은 전혀 이쁘지 않아서 디자인을 입힙니다.
그래서 그 아이는 display: none 하고, 이쁜 디자인을 만들어서 누르면 input file이 열리도록 코딩합니다.
<img
src="@/assets/img-add-orange-90.svg"
@click="$refs.file.click()" />
<input
ref="file"
accept="image/*"
type="file"
style="display: none"
@change="changeFile">
디자인된 이미지를 누르면 숨겨진 input이 클릭되도록 합니다.
이미지가 선택되면 changeFile 이벤트를 통해서 preview 이미지를 만들고, 서버에 보낼 이미지 데이터를 갖고 있으면 됩니다.
<img
v-if="previewImg"
class="review__preview"
:src="previewImg">
<img
v-if="previewImg"
class="cancel-icon"
src="@/assets/ic-delete-white-gray-24.svg">
// 파일 이름
const imgName = ref<string>('');
// 파일 데이터 (API로 넘겨줄 폼 데이터)
const imgData = new FormData();
// 파일 변경 이벤트
const changeFile = async (e: any) => {
imgName.value = e.target.files[0].name;
imgData.append('file', e.target.files[0], imgName.value);
previewImg.value = window.URL.createObjectURL(e.target.files[0]);
};
리뷰를 등록하는 이벤트입니다.
중요한 것은 우선 리뷰를 등록 후, 리뷰에 대한 ID를 가져와서 이미지 업로드 API를 타야 합니다.(만약 이미지를 등록하지 않는다면 타지 않도록)
const clickRegister = async () => {
console.log('clickRegister');
const { meta, content } = await reviewService().createReview(reviewData);
if (imgName.value && meta.result === 'success') {
imgData.append('reviewId', content.reviewId.toString());
const result = await imgUpload(imgData);
if (result.meta.result === 'fail') {
alert('알수없는 이미지 등록 오류 입니다.');
}
}
console.log(meta, content);
if (meta.result === 'success') {
alert(content.msg);
await root.$router.push(`/store/${props.storeId}`);
}
};
백엔드 쪽 이미지 업로드 API입니다.
폼 데이터로 받은 파일을 AWS S3에 넣어야 합니다.
aws-sdk 모듈을 썼고, 이미지 이름이 겹치지 않도록 uuid를 사용했습니다.
이미지 업로드에 성공하면 경로를 받습니다.
그 후 reviewId를 키값으로 리뷰 이미지 컬럼에 받은 경로 값을 업데이트합니다.
const AWS = require('aws-sdk');
const { v4: uuidv4 } = require('uuid');
const parser = require("lambda-multipart-parser");
const uploadImage = async (event, context, cb) => {
try {
const s3 = new AWS.S3();
const result = await parser.parse(event);
const { reviewId } = result;
const { content, contentType } = result.files[0];
const uuid = uuidv4();
const s3Params = {
Bucket: 'dinner-project-eat',
Key: `${uuid}`,
Body: content,
ACL: 'public-read',
ContentType: contentType,
};
const { Location } = await s3.upload(s3Params).promise();
const update = await updateReviewImg(Location, reviewId);
if (!update) await cb(null, createResponse(500, errorMsg('에러')));
await cb(null, createResponse(200, successMsg(Location)));
} catch (e) {
console.log(e);
await cb(null, createResponse(500, errorMsg(e)));
}
};
exports.updateReviewImg = async (path, reviewId) => {
try {
await mysql.connect();
const query = `UPDATE review SET review_custom_img = '${path}' WHERE review_id = ${Number(reviewId)}`
await mysql.query(query);
return true;
} catch (e) {
return false;
} finally {
await mysql.quit();
}
}
아! 저렇게 해도 안 될 경우에는 AWS API Gateway에서 해당 폼 데이터를 잘 받을 수 있도록 설정되어있는지 확인합니다. (저는 뭐가 문제인지 몰라서 엄청 헤매었습니다.)
API Gateway -> 해당 프로젝트 -> 설정
컬럼에 잘 들어간 것을 확인할 수 있습니다.
이미지도 S3에 잘 들어가서 보이는 것도 확인됩니다.
사내에서만 사용하기 때문에 AWS S3의 권한은 다 풀었습니다.
나중에는 더 디테일하게 파봐도 재미있을 것 같습니다.
'Javascript > 삽질' 카테고리의 다른 글
로그인 프로세스 개선 - Axios 통신 한줄기로 만들기 (0) | 2021.05.31 |
---|---|
Node.js - AWS Lambda 용량 줄이기(Layer를 사용하자) (0) | 2021.02.28 |
javascript - JWT 로그인 및 세션 유지 (0) | 2021.02.07 |
화면에 특정 DOM 이 보이는가? - InterSectionObserver API (4) | 2020.09.03 |
Firebase realtime database pagination 삽질기 (0) | 2020.05.25 |