Express.js)multipart/form-data : Multer로 Image 파일 저장하기.

김명성·2022년 6월 29일
0

Javascript에서 거의 모든 데이터는 text data이다.
배열, 객체 상관없이 사람이 읽을 수 있는 모든 것은 text data라고 할 수 있다.

그렇지만 image는 binary data이다.
image는 text data가 아닌 byte로 저장해야 하기에 binary data로 저장해야 하기 때문이다.

binary data
컴퓨터에서 저장되는 모든 데이터는 binary data이다.
일반적으로 string 형식은 텍스트 파일로 변형해서 사용하기에 binary data는 string이 아닌 이미지, 미디어 파일들을 파일을 의미하는 것으로 사용되고 있다.

JSON format은 텍스트 데이터로만 작업하기에 binary data를 다룰 수 없다.
그렇다면 image파일을 backend로 보내는 요청을 어떻게 작성해야 할까?

다행히 브라우저와 Javascript에 해당 기능이 built-in 되어 있다.

먼저 front-end에서 사용할 때에는, JSON.stringify로 보낼 데이터 대신
formData built-in 생성자 함수를 통해 formData를 전송한다.

front-end

  		//JSON대신 formData를 통해 전송한다. 
        const formData = new FormData()
        formData.append('email', formState.inputs.email.value)
        formData.append('name', formState.inputs.name.value)
        formData.append('password', formState.inputs.password.value)
        // 후에 express.js의 multer에서 사용하는 key값으로 설정한다.(image)
        formData.append('image', formState.inputs.image.value)
        
       const responseData = await sendRequest(
          'http://localhost:5050/api/users/signup',
          'POST',
         //JSON.stringfy({}) 대신 formData를 보낸다.
          formData,
         
          // formData는 자동으로 헤더를 추가하기에 수기작성할 필요가 없다.
          //{
          //  'Content-Type':'application/json'
          //},
        )  
        login(responseData.user.id);
        navigate('/');
      }catch(err){}
    }
}

back-end

  1. Multer configuration.
const multer = require('multer')
const uuid = require('uuid/v1')

// MIME_TYPE은 기본적으로 어떤 종류의 파일을 다룰 수 있는지 알려준다.
// Multer는 40여개의 MIME type을 제공한다.
const MIME_TYPE_MAP = {
  'image/png': 'png',
  'image/jpeg': 'jpeg',
  'image/jpg': 'jpg',
}

// 부착한 middleware의 실제 동작.
// 저장할 위치와 파일에 대해 정의한다.
const fileUpload = multer({
  // 500000bytes. 500KB로 업로드를 제한한다.
  limits: 500000,
  // storage는 저장소를 뜻하고,
  // multer는 built-in disk storage driver를 갖고 있다.
  storage: multer.diskStorage({
    // 파일이 저장되는 곳을 정하는 destination
    destination: (req,file,cb) => {
      // 첫번째 arguments는 error message
      // 두번째 arguments는 파일이 저장되는 곳으로, 실제로 폴더를 생성하여 디스크 저장소를 구성한다.
      cb(null,'uploads/images')
    },
    // 파일 이름을 작명할 수 있는 filename
    filename: (req,file,cb) => {
      // 첫번째 arguments는 error message
      const extractMimeType = MIME_TYPE_MAP[file.mimetype]
      cb(null,uuid() + '.' + extractMimeType)
    }
  }),
  //  multer를 구성하는데 사용하는 객체를 전달하는 fileFilter
  // frontend에서 1차적으로 filtering하지만,
  // hacking 및 accept attribute 변경 등으로 바뀔 수 있기에
  // backend 에서 한번 더 filtering 과정을 거친다.
  fileFilter: ((req,file, cb) => {
    const isValid = !!MIME_TYPE_MAP[file.mimetype];
    let error = isValid ? null : new Error ('유효하지 않은 파일 형식입니다.')
    // fileFilter의 2번째 인자는, 해당 파일을 수락할지에 대한 boolean값이다.
    cb(error, isValid);
  })
})

module.exports = fileUpload;
  1. use Multer
router.post(
  '/signup',
  
	// multer middleware 부착 (fileUpload.single('image'))
	// key 값이 image인 파일을 가져온다.
  fileUpload.single('image'),
  [
    check('name').isLength({
      min: 3
    }),
    check('email').normalizeEmail().isEmail(),
    check('password').isLength({
      min: 8,
      max: 14
    })
  ], usersControllers.signup)

multipart/form-data : binary data를 저장할 때 사용하는 content-type이다.

0개의 댓글