SENTENCE U | Day 23 (이미지업로드/클라우드타입 배포자동화)

블로그 이사 완료·2023년 1월 30일
0
post-thumbnail

유저 아바타 변경 기능

multer를 사용해보자

이미지 업로드 버튼 클릭 시 파일을 첨부할 수 있도록 input태그를 사용했다.

<Upload htmlFor='avatar'>
  이미지 업로드
  <input type='file' id='avatar' name='avatar' onChange={onUploadHandler} />
</Upload>

onUploadHandler 함수 실행 시 유저가 input창에서 선택했던 파일을 FormData를 사용해 avatar라는 키의 값으로 넣어준다.

그리고 post통신으로 서버에 데이터를 보낸다. body에는 formData가 들어간다.

const onUploadHandler = useCallback(
  (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append('avatar', e.target.files[0]);
    fetch(`${process.env.API_SERVER}/api/users/${userId}/avatar/upload`, {
      method: 'POST',
      body: formData,
    })
      .then((res) => res.json())
      .then(() => refetch())
      .catch((error) => console.error(error));
  },
  [userId, refetch],
);

모든 통신에 axios를 사용했는데 왜 여기는 fetch를 사용했는가?

axios로 파일 통신하면 버전에 따라 문제가 발생할 수 있다고 한다. 그래서 여기서만 fetch를 사용했다.

또, formData에 append를 사용해서 파일을 넣었는데 console.log(formData)를 찍어보면 값을 볼 수 없었다.

formData의 값을 console.log로 볼 수 없는 원인

한참을 헤메다가 위 블로그에서 원인을 찾았고, for in문과 for of문을 사용하면 확인이 가능하다는 것을 알았다.

자 이제 그럼 서버로 파일을 넘겼으니 express환경에서 처리해보자.

multer라이브러리를 사용하면 프론트에서 보낸 파일을 서버에서 처리할 수 있다.

npm i multer
import fs from 'fs';
import multer from 'multer';

(function () {
  const dir = 'src/assets/avatars';
  if (!fs.existsSync(dir)) {
    console.log('src 폴더가 없습니다. 폴더를 생성합니다.');
    const subDirs = dir.split('/');
    let currentDir = '';
    for (const subDir of subDirs) {
      currentDir += subDir + '/';
      if (!fs.existsSync(currentDir)) {
        fs.mkdirSync(currentDir);
      }
    }
  }
})();

const storage = multer.diskStorage({
  limits: { fileSize: 50 * 1024 }, // 파일크기 500kb 제한
  // 파일 저장 경로

  destination: (req, file, cb) => {
    cb(null, 'src/assets/avatars/');
  },
  // 파일 이름 변경
  filename: (req, file, cb) => {
    cb(null, req.params.id + file.originalname);
  },
});
const upload = multer({ storage });

multer의 사용법은 인터넷을 찾아보면 다양하게 나와있다.

일단 나는 서버의 하드에 저장하기 위해 diskStorage를 사용하고 아래와 같은 옵션을 지정했다.

  • limits : fileSize 50 * 1024 (500kb)
  • destination : src/assets/avatars/
  • filename : req.params.id + file.originalname (유저id + 파일명)

서버에 src/assets/avatars/ 경로가 없으면 생성하도록 맨 위에는 즉시실행함수를 작성해서 경로를 생성할 수 있도록 했다.

이제 비로소 multer는 미들웨어로 프론트에서 파일을 받으면 서버의 폴더에 저장한다.

저장한 파일 유저의 아바타로 설정하기

router.post('/users/:id/avatar', upload.single('avatar'), async (req, res) => {
  const url = `https://www.sentenceu.co.kr/src/assets/avatars/${req.params.id}${req.file.originalname}`;
  await User.updateOne({ _id: req.params.id }, { $set: { userAvatar: url } })
    .then((user) => {
      if (!user) return res.status(403).json({ message: 'User not found.' });
      return res.status(200).json({ message: 'Upload Success' });
    })
    .catch((error) => res.status(500).json({ message: error.message }));
});

post API를 실행하고 multer미들웨어를 통과하면 이제 유저의 아바타를 업로드한 파일로 설정해줘야한다.

서버에 저장한 파일의 경로를 url변수로 저장하고 params로 받은 id로 유저를 검색해 해당 유저의 아바타 이미지 경로를 url로 변경한다.

개발환경에서는 잘 설정 되던게 배포를 하고나면 이미지의 경로를 찾지 못하는 문제가 발생했다.

해결방법은 express의 정적파일 서빙에 있었다.

multer를 통해 upload 폴더 속에 저장한 이미지 접근하기

홈페이지 접속 시 build/index.html 파일을 서빙해준 것처럼 유저의 이미지에도 접근 할 수 있도록 src폴더를 설정해주면 된다.

app.use('/src', express.static(path.join(__dirname, 'src')));

클라우드타입 배포 자동화

클라우드타입에 배포되어있는 내 서버는 깃허브 레포와 연동되어 Github push 후 서버를 재배포해야하는 번거로움이 있었다.

클라우드타입은 Github Actions로 배포 자동화 기능을 제공하고있다.

Github Actions로 배포자동화 하기

위의 링크에서 알려준 것처럼 설정하면 서버 레포지토리에 push할 때마다 클라우드타입 서버배포가 자동화로 이루어진다.

profile
https://kyledev.tistory.com/

0개의 댓글