s3에 node.js로 이미지 올리기

milmil·2022년 7월 24일
0

노드와 나

목록 보기
6/8

S3에 이미지를 올려보자

자나 깨나 과금 조심

AWS는 복잡한 것도 있지만... 잘못하면 과금 될 수 있어서 조심해야 한다.
나는 예전에 실습하다가 EC2 인스턴스를 두 개 이상 켜놓고 안 꺼서 요금이 청구된 적 있다.

무려 20달러나....

그렇게 많은 돈은 아니지만 소득이 없는 사람에게는 큰 금액이었다. 다행스럽게도 이메일로 반성문을 제출했더니 환불받을 수 있었다. (적은 금액은 그래도 돌려준다.) 그뒤로 무서워서 얼씬도 하지 않았지만 이번에 이미지 업로드를 위해 S3를 이용해보았다. 어쨌뜬 AWS를 이용할 때는 과금이 발생하지 않도록 설정에 주의하고, 과금 알림을 설정해놓고 메일을 잘 체크하자.

S3인스턴스를 만들고 퍼블릭 설정을 하자

{
  "Id": "Policy1658663882176",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1658663877057",
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::${BucketName}/",
      "Principal": "*"
    }
  ]
}

정책 설정에 들어가서 이처럼 json으로 설정을 넣는다
BucketName에 자신의 Bucket이름을 쓴다
그리고 IAM 유저 추가해서 AmazonS3FullAccess 권한을 준 뒤 액세스 키와 시크릿 키를 복사하고 절대 외부에 노출되는 일이 없게 하자
나는 프로젝트 .env파일에 환경변수로 추가할 것이다.

이제 여기다 올려야 됨.

패키지 설치하기

지난번 글에서는 이제 서버 폴더에다 이미지를 업로드했는데 여기서 사용했던 multer를 이번에도 쓴다. 그런데 다른 점은 s3에 업로드 하기 위해 multer-s3도 설치한다는 것. 그리고 sdk도 설치할 건데 주의할 점은 multer-s3가 2.0 버전이면 sdk도 2.0버전을, 3.0이면 3.0버전을 써야 한다는 것이다. 지금은 multer-s3을 설치하면 자동으로 3버전이 설치될 건데 인터넷 자료를 참고하면 aws sdk를 2.0 버전을 쓰는 것들이 있어서 오류가 날 수 있음. 물론 multer-s3을 설치하면 콘솔에 의존성 관련해서 친절하게 알려준다. 이 글에서의 버전.

"@aws-sdk/abort-controller": "^3.127.0",
"@aws-sdk/client-s3": "^3.135.0",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
$ yarn add @aws-sdk/abort-controller @aws-sdk/client-s3 multer multer-s3

클라이언트 객체 만들기

import dotenv from 'dotenv';
import { S3Client } from '@aws-sdk/client-s3';

dotenv.config();

const s3 = new S3Client({
  region: 'ap-northeast-2',
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY,
    secretAccessKey: process.env.S3_ACCESS_SECRET,
  },
});

export default s3;

클라이언트 객체를 만든다.

업로드 미들웨어 만들기

import dotenv from 'dotenv';

import multer from 'multer';
import multerS3 from 'multer-s3';

import s3 from '../config/s3.js';

dotenv.config();

const uploadImage = multer({
  storage: multerS3({
    s3,
    bucket: process.env.S3_BUCKET_NAME,
    contentType: multerS3.AUTO_CONTENT_TYPE,
    key: function (req, file, cb) {
      cb(null, `${Date.now()}_${file.originalname}`);
    },
  }),
  limits: { fileSize: 1 * 1024 * 1024 },
});

export default uploadImage;

미들웨어 등록

router.post('/upload', uploadImage.single('img'), async (req, res, next) => {
  //이미지 업로드함
  const { id } = req.decoded;
    await member.update(
      {
        profile_image: req.file.location,
      },
      { where: { id } }
    );
    res.send(req.file.location);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

이미지를 업로드하고 url을 db에 저장한다.

아주 간단하다.

프론트엔드(리액트)

useState

    const [image, setImage] = useState("");
  const [imageUrl, setImageUrl] = useState("");

form

 <form onSubmit={onSubmit}>
        {imageUrl ? (
          <>
            <img src={imageUrl} alt="" width={50} />
          </>
        ) : (
          ""
        )}
        <input type="file" onChange={onChange} />
        <button type="submit">업로드</button>
      </form>

onChange이벤트

  const onChange = (e) => {
    setImage(e.target.files[0]);
  };

onSubmit이벤트


  const onSubmit = async (e) => {
    e.preventDefault();

    try {
      const formData = new FormData();
      formData.append("img", image);
      const res = await axios.post("http://localhost:3001/api/image/upload", formData);
      alert("업로드 성공!");
      setImageUrl(res.data);

    } catch (err) {
      console.error(err);
    }
  };

그러면 이미지가 업로드되고 이렇게 표시된다


이제 변경된 프로필 이미지가 표시된다

profile
쓰고 싶은 글만 씀

0개의 댓글