Skip to content

NCP Object Storage를 이용하여 이미지 업로드하기

Donghyun Kim edited this page Nov 6, 2020 · 6 revisions

Object Storage

→ 네이버 클라우드 플랫폼 서비스 중 하나

→ 사용자가 언제 어디서나 원하는 데이터를 저장하고 탐색할 수 있도록 파일 저장 공간을 제공하는 서비스

→ AWS S3 compatible API를 제공하므로, S3를 활용한 툴을 Object Storage에서도 사용할 수 있음

목표

Object Storage를 사용해서 이미지를 선택하면 서버에 업로드되고, 저장된 이미지 주소를 마크다운 형식으로 작성해보기

0. 실행 순서

  1. NCP(https://www.ncloud.com/) 사이트에서 Object 생성
  2. FE에서 선택한 이미지 파일을 서버에 요청보내는 코드 작성
  3. BE에서 요청받은 객체를 NCP에 업로드 후, 응답으로 주소값 반환
  4. FE에서 응답받은 주소값으로 마크다운 형식으로 작성

1. Naver Cloud 사이트에서 Object 생성하기

https://www.ncloud.com/product/storage/objectStorage 접속 후 이용 신청

  • 아래와 같은 화면에서 버킷 생성 버튼 클릭
  • 권한은 공개 권한으로 설정

image

2. FE에서 선택한 이미지 파일을 서버에 요청보내는 코드 작성

먼저 file을 입력받기 위한 간단한 jsx코드를 작성합니다

import React, { useState } from 'react';

function TestPage() {
	let [imgPath, setImgPath] = useState('');
	  return (
	    <div>
	      <input type="file" accept="image/png" onChange={submitHandler}></input>
	    </div>
	)
}

export default TestPage;

이후, 선택된 파일을 서버에 보내주는 이벤트 코드를 작성합니다

서버와의 비동기 통신을 사용하기 위해 axios를 설치해줍니다

서버로 이미지를 보낼때에는 FormData라는 객체에 담아서 보내야하며 'filename' 이라는 이름으로 추가해줍니다

npm install axios
import axios from 'axios';
const submitHandler = (event) => {
    if (event.target.files !== null) {
      //FormData 생성
      const fd = new FormData();
      //FormData에 key, value 추가하기
      fd.append('filename', event.target.files[0]);
      // axios 사용해서 백엔드에게 파일 보내기
      axios
        .post(`/api/test`, fd, {
          headers: { 'Content-Type': 'multipart/form-data;charset=utf-8;' },
        })
        .then((res) => {
          //응답으로 받은 url 저장하기 (응답 내용의 표시나 방법은 백엔드와 결정해야한다.)
          setImgPath(res.data);
        })
        //에러가 날 경우 처리
        .catch((error) => {
          console.log(error.response);
        });
    }
  };

3. BE에서 요청받은 객체를 이용하여 NCP에 등록 후, 응답으로 주소값 반환

npm install multer multer-s3 aws-sdk

multer : 프론트로부터 받은 파일에 대한 처리를 도와주는 라이브러리

multer-s3 : 업로드된 파일을 NCP에 바로 업로드할 수 있도록 도와주는 라이브러리

aws-sdk : AWS S3에서 제공하는 Javascript SDK를 이용할 때 필요한 라이브러리

3-1) NCP S3 설정

아래의 코드는 네이버에서 제공해주는 예제 코드입니다

우선 ACCESS_KEYSECRET_KEY는 네이버 클라우드 홈페이지에서 얻을 수 있습니다.

마이페이지 > 계정관리 > 인증키 관리에 접속 후, API 인증키가 없다면 신규 API 인증키 생성을 통해 키를 생성합니다.

image

이후, 얻어온 키는 환경변수 설정을 통해 ⭐Private⭐하게 보관해줍니다

const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const path = require('path');

const endpoint = new AWS.Endpoint('https://kr.object.ncloudstorage.com');
const region = 'kr-standard';
const access_key = process.env.ACCESS_KEY;
const secret_key = process.env.SECRET_KEY;

const S3 = new AWS.S3({
  endpoint,
  region,
  credentials: {
    accessKeyId: access_key,
    secretAccessKey: secret_key,
  },
});

3-2) 프론트에서 요청을 보낸 이미지를 업로드하는 과정

우선 '/test'로 post 요청을 처리하기 위해 다음과 같이 router를 작성해 줍니다

이후 multer storage를 multer-s3 라이브러리를 이용하여 작성해줍니다.

이때 저장되는 파일의 이름을 중복방지를 위해 현재시간으로 설정해줍니다

등록한 upload 변수는 파일이 하나이므로 upload.single로 작성하며, FormData의 key값을 적어주어 미들웨어로 등록해줍니다

const router = require('express').Router();
const multer = require('multer');
const multerS3 = require('multer-s3');
const path = require('path');

const upload = multer({
  storage: multerS3({
    s3: S3, // 위에서 정의한 S3 Object
    bucket: 'issue', // 버킷 이름
    contentType: multerS3.AUTO_CONTENT_TYPE, // 자동을 콘텐츠 타입 세팅
    acl: 'public-read', // 클라이언트에서 자유롭게 가용하기 위함
    key: (req, file, cb) => {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    },
  }),
  limits: { fileSize: 5 * 1024 * 1024 }, // 용량 제한
});

router.post('/test', upload.single('filename'), (req, res) => {
  res.send(req.file.location);
};

module.exports = router;

multer를 등록해주면 라우터에서 다음과 같이 사용할 수 있습니다

image

const file = req.file
console.log(req.file)

3-3) 코드 정리

프론트는 NCP에 올라가게 될 파일의 위치가 필요하니 req.file.location변수를 보내줍니다

const router = require('express').Router();
const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');

const path = require('path');

const endpoint = new AWS.Endpoint('https://kr.object.ncloudstorage.com');
const region = 'kr-standard';
const access_key = process.env.ACCESS_KEY;
const secret_key = process.env.SECRET_KEY;

const S3 = new AWS.S3({
  endpoint,
  region,
  credentials: {
    accessKeyId: access_key,
    secretAccessKey: secret_key,
  },
});

const upload = multer({
  storage: multerS3({
    s3: S3,
    bucket: 'issue', // 버킷 이름
    contentType: multerS3.AUTO_CONTENT_TYPE, // 자동을 콘텐츠 타입 세팅
    acl: 'public-read', // 클라이언트에서 자유롭게 가용하기 위함
    key: (req, file, cb) => {
      cb(null, new Date().valueOf() + path.extname(file.originalname));
    },
  }),
  limits: { fileSize: 5 * 1024 * 1024 }, // 용량 제한
});

router.post('/test', upload.single('filename'), (req, res) => {
  res.send(req.file.location);
};

module.exports = router;

4. FE에서 응답받은 주소값으로 마크다운 형식으로 작성

4-1) React State를 이용하여 이미지 주소 값 등록

→ 서버로부터 반환받은 파일이름과 object 주소를 이용하여 state를 업데이트 시켜줍니다 image

import React, { useState } from 'react';
import axios from 'axios';

function TestPage() {
  const submitHandler = (event) => {
    if (event.target.files !== null) {
      const fd = new FormData();
      fd.append('filename', event.target.files[0]);
      axios
        .post(`/api/test`, fd, {
          headers: { 'Content-Type': 'multipart/form-data;charset=utf-8;' },
        })
        .then((res) => {
          setImgPath(`https://kr.object.ncloudstorage.com/issue/` + res.data);
        })
        .catch((error) => {
          console.log(error.response);
        });
    }
  };
  let [imgPath, setImgPath] = useState('');
  if (imgPath == '') {
    return (
      <div>
        <input type="file" accept="image/png" onChange={submitHandler}></input>
      </div>
    );
  } else {
    return <a href={imgPath}>마크다운 형식 : {imgPath}</a>;
  }
}

export default TestPage;

5. Issue

1 ) 해당 링크를 클릭하면, 링크 이동이 아닌 파일이 다운로드 되어지는 현상

💡파일을 업로드할 때, 다음과 같이 옵션을 추가해주어 해결

ACL: 'public-read' ContentType: 'image/png'

  (async () => {
    await S3.upload(
      {
        Bucket: bucket_name,
        Key: object_name,
        Body: fs.createReadStream(local_file_name),
        ACL: 'public-read',
        ContentType: 'image/png',
      },
      options
    ).promise();
  })();

참고자료

https://docs.ncloud.com/ko/storage/storage-8-4.html

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property

https://krpeppermint100.medium.com/js-react에서-express로-이미지-파일-올리기-multer-f398adf6dbdd

https://victorydntmd.tistory.com/39

Clone this wiki locally