강디너의 개발 일지

이미지 업로드 - 프론트 부터 AWS S3 까지의 과정 본문

Javascript/삽질

이미지 업로드 - 프론트 부터 AWS S3 까지의 과정

강디너 2021. 4. 25. 21:21
728x90

사용자가 이미지를 선택할 때부터 백엔드 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의 권한은 다 풀었습니다.

나중에는 더 디테일하게 파봐도 재미있을 것 같습니다.

커피한잔...
Comments