먹짱(쇼핑몰 프로젝트) - 어드민 페이지(2) - 서버에 사진 저장하고 띄우기

ryan·2022년 6월 8일
0

📑 개요

  • 어드민 페이지 기능 중 하나인 '상품 등록'을 구현하는 과정에서 마주친 문제인 'input을 통해 서버에 이미지 저장하고 화면에 띄우기'를 어떻게 해결했는지 정리하여 작성했다.

이미지를 등록하고 화면에 띄우기까지의 흐름

  • 이번 프로젝트에서 우리가 이미지를 띄우는 과정을 간단하게 표현해봤다. (발표 자료로 사용)

❗ 문제 해결 과정 (1) - 이미지 서버로 보내기

문제의식

기존에 이미지를 저장하고 띄우는 방식은 인터넷에 떠도는 이미지의 주소를 복사해서 db에 링크를 바로 넣었고, 이미지를 띄울 때도 db에 넣은 링크를 가져와서 img src에 적용하는 방식이였다.

이런 방식은 서버 통신을 활용한 방식이 아닐 뿐더러 사용하고 있는 주소의 이미지에 수정이나 삭제가 발생할 경우 알아차리기 힘들고 대처도 어렵다.

문제를 해결하기 위해선 서버 통신을 이용해 이미지 파일을 서버에 저장하여 불러올 때는 저장된 경로에서 가져오는 방식을 사용해야한다.

input type='file'

  • input태그의 file type을 사용하면 클릭했을 때 유저의 로컬 파일을 업로드할 수 있는 기능이 마련된다.

  • file을 서버에 전송하기 위해서는 formData형식으로 가공해서 보내야 한다.

    • mdn에서도 서버에 데이터를 전송하려면 html form을 사용하라고 적극 권장하고 있으며, 그 이유는 클라이언트가 http request를 사용 친화적으로 보낼 수 있기 때문이라고 명시했다.
  • input의 multiple attribute를 추가하면 여러개의 파일을 업로드 할 수 있다.

formData 객체

  • formData가 서버에 전송되는 경우, Content-Type은 multipart/form-data로 알아서 지정되기 때문에, 서버 요청을 보낼 때 따로 header에 type을 설정할 필요가 없다.(지정할 경우 오히려 에러가 발생한다.)

  • formData에 append 메서드를 사용하며 폼 필드를 추가할 수 있다. 응요하면 업로드한 이미지를 formData에 추가하기 위해서는 새로운 필드를 추가해야만 한다.

    • 이 때 필드의 이름은 중복되도 상관없다.
    • set 메서드도 append와 동일한 역할을 하지만 중복된 이름을 모두 삭제하고 하나의 필드만 구성한다.

코드

  • 위에서 학습한 내용을 바탕으로 코드를 작성했으며 흐름은 다음과 같다.
    1. submit 버튼이 눌리면 formData 인스턴스 생성
    2. append를 사용하여 필드를 추가
    3. 백엔드 api를 이용하여 formData를 그대로 전송
admin.js

<input style='display:none' class='input' type='file' id='fileUpload' value='파일 선택'/>
let imgData = new FormData(); 
imgData.append('image', $fileUpload.files[0]);
let uploadedImage = await Api.formPost('/api/product/upload', imgData);

------

백엔드 api

async function formPost(endpoint, data) {
  const apiUrl = endpoint;

  const res = await fetch(apiUrl, {
    method: 'POST',
    headers: { // 별다른 header 설정은 필요없다. 
      Authorization: `Bearer ${sessionStorage.getItem('token')}`,
    },
    body: data, // body에 formData를 가공없이 그대로 넣는다. 
  });
  if (!res.ok) {
    const errorContent = await res.json();
    const {reason} = errorContent;
    throw new Error(reason);
  }
  const result = await res.json();
  return result; // 파일명을 반환한다.
}

❗ 문제 해결 과정 (2) - 화면에 띄우기

static 경로 요청을 통해 정적 파일 가져오기

express에서는 express.static이라는 내장 모듈을 통해 정적 파일을 제공한다.

프론트에서 이미지 파일 경로를 지정할 때도 위의 static 경로를 활용하여 불러오게 되며 아래와 같이 코드를 구성했다.

코드

상품 목록 페이지
const domain = window.location.host; // 도메인 가져오기
for (let e of data) {
  const {img} = e;
  $itemListFlexbox.insertAdjacentHTML(
   'beforeend',
    `<img class='img' src='${'http://' + domain + '/static/' + img}'/>` 
    );
  }

app.js 
...
app.use('/static', express.static(__dirname + '/public'));
  • 이번 프로젝트는 파일 서버를 로컬로 지정했기 때문에, static 경로를 보면 로컬의 public이라는 폴더에서 이미지를 가져오게 된다.

  • 프론트에서 요청할 때는 http 경로를 사용해야 하며, domain 주소를 추출하기 위해 window객체를 사용했다.

  • img는 파일명의 문자열 데이터이며, 경로의 마지막에 붙여주면 public에서 일치하는 파일명을 가져오게 된다.


화면 예시

  • 상품 등록을 통해 이미지가 저장되고, 정상적으로 이미지가 출력되는 것을 확인할 수 있다.

profile
프론트엔드 개발자

0개의 댓글