[Node.js] Multer

강경서·2023년 8월 21일
0
post-thumbnail

시작하기 전

클라이언트에서 form을 통해 데이터를 서버에게 전달할 때 텍스트를 전달 할 수도 있고, 이미지를 전달 할 수도 있습니다. 하지만 텍스트와 이미지의 Content-Type은 서로 달라 HTTP 프로토콜의 바디 부분 함께 들어갈 수가 없습니다. 이를 위해 Multipart가 생겼습니다.

Multipart는 클라이언트가 요청을 보낼 때, HTTP 프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것입니다.


multipart/form-data

form 태그의 enctype 속성은 form data가 서버로 제출될 때 해당 데이터가 인코딩되는 방법을 명시합니다.

  • application/x-www-form-urlencoded :
    기본값으로, 모든 문자들은 서버로 보내기 전에 인코딩됨을 명시합니다.
  • multipart/form-data : 모든 문자를 인코딩하지 않음을 명시합니다. 이 방식은 form 요소가 파일이나 이미지를 서버로 전송할 때 주로 사용합니다.
  • text/plain : 공백 문자(space)는 “+” 기호로 변환하지만, 나머지 문자는 모두 인코딩되지 않음을 명시합니다.

일반적으로 텍스트 데이터는 주로 URL 인코딩되어 전송됩니다, 하지만 이미지, 영상, 음성과 같은 데이터는 바이너리 데이터이므로 텍스트로 표현하기 어렵기 때문에 multipart/form-data 방식을 사용하여 데이터를 전송합니다.

바이너리 데이터는 컴퓨터가 사용하는 이진(binary) 형태의 데이터를 나타냅니다. 이진 데이터는 텍스트 데이터와 달리 사람이 바로 이해하기 어려운 형태의 숫자, 비트, 바이트 등으로 구성된 데이터를 의미합니다.


Multer

Multer는 파일 업로드를 위해 사용되는 multipart/form-data 를 다루기 위한 node.js 의 미들웨어 입니다. 효율성을 최대화 하기 위해 busboy 를 기반으로 하고 있습니다.

busboy는 HTML form 데이터를 파싱하는 node.js 모듈입니다.


Multer 사용하기

Multer를 설치합니다.

 npm install multer

Multer는 body 객체와 한 개의 file 혹은 여러개의 files 객체를 request 객체에 추가합니다. body 객체는 폼 텍스트 필드의 값을 포함하고, 한 개 혹은 여러개의 파일 객체는 폼을 통해 업로드된 파일들을 포함하고 있습니다.

const express = require('express')
const multer  = require('multer')
const upload = multer({ dest: 'uploads/' })

const app = express()

app.post('/profile', upload.single('avatar'), function (req, res, next) {
  // req.file 은 `avatar` 라는 필드의 파일 정보입니다.
  // 텍스트 필드가 있는 경우, req.body가 이를 포함할 것입니다.
})

app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
  // req.files 는 `photos` 라는 파일정보를 배열로 가지고 있습니다.
  // 텍스트 필드가 있는 경우, req.body가 이를 포함할 것입니다.
})

const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
  // req.files는 (String -> Array) 형태의 객체 입니다.
  // 필드명은 객체의 key에, 파일 정보는 배열로 value에 저장됩니다.
  //
  // e.g.
  //  req.files['avatar'][0] -> File
  //  req.files['gallery'] -> Array
  //
  // 텍스트 필드가 있는 경우, req.body가 이를 포함할 것입니다.
})

텍스트 전용 multipart 폼을 처리해야 하는 경우, 어떠한 multer 메소드 (.single(), .array(), fields()) 도 사용할 수 있습니다.

const express = require('express')
const app = express()
const multer  = require('multer')
const upload = multer()

app.post('/profile', upload.array(), function (req, res, next) {
  // req.body는 텍스트 필드를 포함합니다.
})

multer(opts)

Multer는 옵션 객체를 허용합니다. 그 중 가장 기본 옵션인 dest 요소는 Multer에게 파일을 어디로 업로드 할 지를 알려줍니다. 만일 옵션 객체를 생략했다면, 파일은 디스크가 아니라 메모리에 저장될 것 입니다.

  • dest or storage : 파일이 저장될 위치
  • fileFilter : 어떤 파일을 허용할지 제어하는 함수
  • limits : 업로드 된 데이터의 한도
  • preservePath : 파일의 base name 대신 보존할 파일의 전체 경로

.single(fieldname)

fieldname 인자에 명시된 이름의 단수 파일을 전달 받습니다. 이 파일은 req.file 에 저장될 것 입니다.


.array(fieldname, maxCount)

fieldname 인자에 명시된 이름의 파일 전부를 배열 형태로 전달 받습니다. 선택적으로 maxCount 에 명시된 값 이상의 파일이 업로드 될 경우 에러를 출력할 수 있습니다. 전달 된 배열 형태의 파일은 req.files 에 저장될 것입니다.


.fields(fields)

fields 인자에 명시된 여러 파일을 전달 받습니다. 파일 객체는 배열 형태req.files 에 저장될 것입니다. fields 는 name 과 maxCount (선택사항) 을 포함하는 객체의 배열이어야 합니다.


storage

만일 업로드를 더 제어하고 싶다면, dest 옵션 대신 storage 옵션을 사용할 수 있습니다. Multer는 스토리지 엔진인 DiskStorage 와 MemoryStorage 를 탑재하고 있습니다. 써드파티로부터 더 많은 엔진들을 사용할 수 있습니다.


DiskStorage

디스크 스토리지 엔진은 파일을 디스크에 저장하기 위한 모든 제어 기능을 제공합니다.

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/my-uploads')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now())
  }
})

const upload = multer({ storage: storage })

destinationfilename 의 두가지 옵션이 가능합니다. 두 옵션 모두 파일을 어디에 저장할 지를 정하는 함수입니다.

destination 옵션은 어느 폴더안에 업로드 한 파일을 저장할 지를 결정합니다. 이는 string 형태로 주어질 수 있습니다 (예. '/tmp/uploads'). 만일 destination 옵션이 주어지지 않으면, 운영체제 시스템에서 임시 파일을 저장하는 기본 디렉토리를 사용합니다. destination 을 함수로 사용할 경우, 디렉토리를 생성해야 할 책임이 있습니다. 문자열이 전달될 때, multer는 해당 디렉토리가 생성되었는지 확인합니다.

filename 은 폴더안에 저장되는 파일 명을 결정하는데 사용됩니다. 만일 filename 이 주어지지 않는다면, 각각의 파일은 파일 확장자를 제외한 랜덤한 이름으로 지어질 것입니다. Multer는 어떠한 파일 확장자도 추가하지 않습니다. 사용자 함수는 파일 확장자를 온전히 포함한 파일명을 반환해야 합니다.


MemoryStorage

메모리 스토리지 엔진은 파일을 메모리에 Buffer 객체로 저장합니다. 이에 대해서는 어떤 옵션도 없습니다.

Buffer 객체란 임시 메모리 공간에 저장하는 바이너리 형태의 데이터 객체입니다.

const storage = multer.memoryStorage()
const upload = multer({ storage: storage })

메모리 스토리지 사용시, 파일 정보는 파일 전체를 포함하는 buffer 라고 불리는 필드를 포함할 것입니다. 메모리 스토리지를 사용시, 매우 큰 사이즈의 파일을 업로드 하거나 많은 양의 비교적 작은 파일들을 매우 빠르게 업로드 하는 경우 응용 프로그램의 메모리 부족이 발생 할 수 있습니다.


🧾 Reference

profile
기록하고 배우고 시도하고

0개의 댓글