본문 바로가기

react-shop-web/front & back

이미지 파일을 서버로 보내기

이 게시글에선 dropzone을 통해 파일을 올리면 그 파일을 백엔드에서 multer라는 라이브러리를 이용해서 저장해주고, 그 저장해준 파일의 정보를 프론트로 갖고 올 것이다. 

 

 

onDrop Function 만들기


import React from 'react'
import Dropzone from 'react-dropzone'
import {Icon} from 'antd'
import axios from 'axios'

function FileUpload() {

    const dropHandler = (files) => {

        let formData = new FormData();

        const config = {
            header: {'content-type': 'multierpart/form-data'}
        }
        formData.append("file", files[0])

      axios.post('/api/product/image', formData, config)
        .then(response => {
          if (response.data.success) {
            
          } else {
            alert('파일을 저장하는데 실패하였습니다.')
          }
        })
    }

  return (
    <div style={{display:'flex', justifyContent: 'space-between'}}>
        <Dropzone onDrop={dropHandler}>
                {({getRootProps, getInputProps}) => (
                    <section>
                      <div style={{width:300, height:240, border:'1px solid lightgray', display:'flex', alignItems:'center', justifyContent:'center'}}
                          {...getRootProps()}>
                          <input {...getInputProps()} />
                          <Icon type="plus" style={{fontSize: '3rem'}} />
                    </div>
                    </section>
                )}
        </Dropzone>

          
    </div>
  )
}

export default FileUpload

FileUpload.js

 

위 코드에서 

let formData = new FormData();

        const config = {
            header: {'content-type': 'multierpart/form-data'}
        }
        formData.append("file", files[0])

이 부분을 봐보자.

엑시오스로 서버에 요청을 보낼 때 위 부분을 같이 보내지 않으면 에러가 난다. 

 

 


multipart가 생긴 배경

 

기본적으로 form이 submit 되면 HTTP 헤더에 지정한 타입의 데이터가 Body에 담겨서 서버로 보내지게 됩니다.

 

정리하면 다음과 같습니다.

 

  • HTTP Request의 Body에 클라이언트가 전송하려는 데이터가 담김
  • Body에 들어가는 데이터의 타입을 HTTP Header에 명시해 줌으로써 서버가 타입에 따라 알맞게 처리
  • 해당 Body의 타입을 명시하는 Header가 Content-Type

 

이때 중요한 점은 HTTP Request의 Body가 한 종류의 타입이 대부분이라는 점입니다.

 

Content-Type도 한 종류만 명시할 수 있는데 예를 들어 text이면 text/plain, xml이면 text/xml, png이미지이면 image/png 이런 식으로 명시하여 데이터를 서버로 전송하게 됩니다.

 

하지만 파일 업로드의 상황을 살펴보면 사진을 업로드하는 경우 사진에 대한 설명을 위한 input과 사인 파일을 위한 input 2개가 들어갑니다.

 

위 두 input에 대한 Content-Type은 전혀 다른데, 이미지의 설명에 대한 Content-Type은 application/x-www-form-urlencoded일 것이고, 사진 파일에 대한 Content-Type은 image/png 일 것입니다.

 

두 종류에 대한 Content-Type이 하나의 HTTP Request Body에 들어가야 하는데 이때 2종류의 데이터를 구분해서 넣어주는 방법이 필요해서 multipart라는 개념이 들어가게 되었습니다.


 

https://velog.io/@shin6403/HTTP-multipartform-data-%EB%9E%80

 

HTTP multipart/form-data 란?

프로젝트를 진행하면서 프론트 -> 백엔드로 이미지를 전송하는 경우가 있었다.오늘은 HTTP, multipart, multipart/form-data 세 가지 키워드에 대해 알아보고, 그 중에서 중요한 개념중에 하나인 multipart/for

velog.io

https://velog.io/@wish/%EC%84%9C%EB%B2%84%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B3%B4%EB%82%B4%EA%B8%B0

 

서버로 이미지 보내기에 숨겨진 개념들

서버로 이미지를 보내기 위해서는 어떻게 해야할까?

velog.io

https://jw910911.tistory.com/117

 

HTTP: Content-Type 에 대해 알아보자 (application/json, application/x-www-form-urlencoded, multipart/form-data)

웹 개발을 하게 되면 HTTP에 대해 조금 알아두는 것이 좋습니다. 그중에서 Content-Type에 대한 이해가 부족한 것 같아 정리를 해보았습니다. Content-Type Content-Type은 api 연동시에 보내는 자원을 명시하

jw910911.tistory.com

 

여기까지했다면 일단 프론트 부분은 완성했다. 

 

다음은 서버 부분을 구현해줘야한다.

여기서 한가지 알아야될 점이 있다.

프론트 코드를 보면

 

axios.post('/api/product/image', formData, config)
 
 
이런식으로 요청을 보냈기 때문에
index.js에서도 app.post('/api/product/image') 이런식으로 구현을 해줘야한다.
하지만 index.js 파일 하나에서 모든 request를 다루면 코드가 굉장히 길어진다.
그래서 express js에서 제공해주는 router라는 기능을 이용하여 request 부분들을 나누어 주자.
현재 product에 관한 request이므로 routes 폴더에서 product.js 파일을 하나 만든다.
그리고 user.js에서 했던 것처럼 유사하게 구현해주면 된다.

 

app.use('/api/users', require('./routes/users'));
app.use('/api/product', require('./routes/product'));

server/index.js

 

index.js에 위 코드에서 product 부분을 추가해주게 되면,  서버에서 요청을 받을 때 api product를 타고서 routes/product.js 파일로 가게된다. 그래서 routes.js 파일에서 요청 부분을 구현할 때 엔드포인트가 '/api/product/image' 이런식이 아니라 '/image' 이런식으로 구현해주면 된다.

 

const express = require('express');
const router = express.Router();

//=================================
//             Product
//=================================

router.post('/image', (req, res) => {

    // 가져온 이미지를 저장 해주는 부분 
})

module.exports = router;

server/routes/product.js

 

 이미지를 저장할 때 multer라는 것을 사용해야해서 multer 라이브러리를 다운받자. (multer은 server dependency임)