프로젝트/가말다 - 마일스톤

이미지 파일 서버에 전송 후 저장, 그리고 이미지 주소 이용

58청춘 2023. 8. 26. 13:45
728x90

프로젝트에서 유저와 프로젝트에 사용할 이미지를 저장하기 위한 이미지 서버를 팀 동료가 구축했다.

 

[express] 라즈베리파이 이미지서버 사용

라즈베리파이를 활용해서 이미지서버를 올려보았다. 간단하게 이미지를 받으면 이를 파일로 저장하고, url로 해당 이미지를 띄워주는 간단한 기능을 하는 서버라 크게 어려울 것은 없다. 라이브

supersfel.tistory.com

이미지 서버에서 Post요청과 Delete요청으로 이미지 파일을 관리할 수 있게 구축했기에
이제는 FE에서 이미지 파일을 관리할 수 있는 API를 개발하면 된다.

 

파일 자체를 서버로 보내는것은 개발 공부를 하면서 처음 해보는 것이기에 조사를 해봤다.

  1. 이미지 파일을 자바스크립트 단에서 변형없이 비동기로 제출하려면 form-data 객체를 이용해야한다.
  2. form-data 객체는 간단히 문자열화 할 수 없기에 console.log와 같은 방법으로는 확인이 어렵다.
    불가능은 아니다. get이나 getAll을 이용하거나 객체를 순회하면 값을 읽을 수 있다.
  3. 이미지 파일을 전송할 때 이미지는 base64, buffer, 2진 data 형식으로 전송가능하다.
    이번에는 base64인코딩 형식으로 전송했다.

이렇게 조사를 한 뒤 API 개발을 시작하고 시험을 했는데,

........

역시 한방에 되는 법은 없나보다.

 

문제가 발생했다.

처음에는 단순 cors에러인줄 알았지만

서버에서 cors 허용을 한뒤에도 다른 에러가 발생했다.

 

이 문제는 이미지 파일을 resizing 하는 과정에서 발생했다.

export const resizingImg = async (imgFile: File, maxSizeMB: number, maxWidthOrHeight: number) => {
  const options = {
    maxSizeMB: maxSizeMB,
    maxWidthOrHeight: maxWidthOrHeight
  }
  try {
    if (!(imgFile instanceof Blob) || !(imgFile instanceof File)) {
      return 'instance error';
    }
    if (!imgFile.type.startsWith('image/')) {
      return 'fileType error';
    }
    const compressedFile = await imageCompression(imgFile, options);
    const promise = imageCompression.getDataUrlFromFile(compressedFile);
    return await promise;
  }
  catch(e) {
    console.log(e);
  }
}

위의 코드는 이미지 파일을 받아 지정한 크기와 너비/높이로 이미지를 resizing해주는 코드이다.

문제는 try의 마지막에 있었다.

지금 보면 return 값이 promise라는 값인데, 이 값은 resizing된 이미지 파일의 파일명을 의미한다.

 

즉, 파일 그 자체를 보내야되지만 나는 파일명만 form-data객체에 넣고 이미지 서버에 보낸 것이다.

서버에서 이미지 파일을 받아 동작하기에 당연히 파일명만을 보내 에러가 발생한 것이였다.

 

위의 코드를 다시 손본 결과 아래의 코드로 바뀌게 되었다.

export const resizingImg = async (imgFile: File, maxSizeMB: number, maxWidthOrHeight: number) => {
  const options = {
    maxSizeMB: maxSizeMB,
    maxWidthOrHeight: maxWidthOrHeight
  }
  if (!(imgFile instanceof Blob) || !(imgFile instanceof File)) {
    return 'instance error';
  }
  if (!imgFile.type.startsWith('image/')) {
    return 'fileType error';
  }
  const compressedFile = await imageCompression(imgFile, options);
  const promise = await imageCompression.getDataUrlFromFile(compressedFile);
  return {
    'file': compressedFile,
    'fileName': promise
  }
}

이렇게 바뀐 함수는 file과 fileName을 결과값을 반환해줬다.

위와같이 나누어 반환한 이유는 file은 form-data객체로 감싸 서버에 보낼 용도,

fileName은 이미지를 컴포넌트에서 미리보기 기능을 위해 이미지 파일명만 보냈다.

 

이제 이미지 서버와 통신이 원활하게 동작하는 것을 확인했다.

이미지 파일을 업로드하면 반환 값으로 state: 성공 여부, imageUrl: 이미지 주소 를 받게 되는데

받은 이미지 주소를 DB에 있는 유저의 imageUrl에 넣어주면 된다.

 

이때는 특정 칼럼만 수정하는 것이기에 HTTP 메서드중 Patch를 이용해 BE에 요청을 보냈다.

/**
 * 계정 관리 페이지에서 유저가 이미지를 변경할 때 유저 이미지 변경 요청을 보내는API
 ** PATCH요청
 * @param accessToken : string
 * @param userImgUrl : string
 * @returns db정보 변경 성공 여부
 */
export const updateUserImgApi = async (
  accessToken: string,
  userImgUrl: string,
) => {
  const res = await fetch(`${process.env.REACT_APP_API_URL}/account_manage/userimage`, {
    method: 'PATCH',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      "accessToken": accessToken,
      "userImgUrl": userImgUrl
    })
  })
  return res.json();
};

(최근에 RESTFul 한 API 작성을 목표로 삼았기에 많은 것을 알아보고있다.)

이렇게 작성된 API는 최종적으로 DB를 다루는 코드를 통해 데이터를 수정하게 된다.

async updateUserImage(userId: number, userImgUrl: string) {
  const query = `UPDATE User SET profileImage="${userImgUrl}" WHERE userId="${userId}"`
  const ret = this.sendQuery(query);
  return ret;
}

 

이렇게 해서 이미지 서버에 이미지 업로드 API와 부가적인 API를 다뤄보았다.

이 작업을 통해 배운점은 

  1. 항상 서버측에 API 요청을 보낼때는 서버에서 데이터를 받는 방식을 확인해야한다.
  2. form-data를 이용해 파일을 보내면 파일의 변조가 어려워 보안적으로 좋고,
    서버에서 쉽게 파싱이 가능해 사용에 용이하며,
    큰 용량과 다양한 타입을 지원하기에 범용성이 높기에 사용하는 것
  3. RESTFUL API를 작성하는 것은 앞으로 협업을 하는 개발자 커리어를 시작함에 있어 중요하다.
    아래는 내가 RESTFUL을 공부하며 찾은 좋은 블로그 글들이다.
    시간이 된다면 나도 정리해 글을 작성하도록 해야겠다.
 

[Network] REST란? REST API란? RESTful이란?

자원을 이름으로 구분하여 해당 자원의 상태(정보)를 주고받는 모든 것을 의미즉, 자원의 표현에 의한 상태 전달자원의 표현자원 : 해당 소프트웨어가 관리하는 모든 것자원의 표현 : 그 자원을

velog.io

 

[WEB] 🌐 REST API 구성/특징 총 정리

REST API의 탄생 REST는 Representational State Transfer라는 용어의 약자로서 2000년도에 로이 필딩 (Roy Fielding)의 박사학위 논문에서 최초로 소개되었습니다. 로이 필딩은 HTTP의 주요 저자 중 한 사람으로 그

inpa.tistory.com

 

728x90