Node

[Node.js] 파일 업로드(multer) 사용해보기

YaluStar 2023. 3. 6. 01:23

안녕하세요.

이번에는 파일 업로드 기능을 사용해 보겠습니다.

 

1. 파일 업로드

  • 클라이언트 -> 서버 데이터 전송하는 법

 

2. multer

  • npm install multer
  • 파일 업로드를 위해 사용되는 미들웨어
  • express로 서버를 구축할 때 가장 많이 사용되는 미들웨어
  • multer로 파일 업로드 실행 시 파일 이름은 랜덤 hash 값으로 설정이 되며 확장자 설정도 되어 있지 않으며, 추가 작업이 필요하다.
const multer = require('multer');

 

2-1. multer 세부 설정

  • storage : 저장할 공간에 대한 정보
    • diskStorage : 파일을 디스크에 저장하기 위한 모든 제어 기능을 제공
    • destination : 저장할 경로
    • filename : 파일명

 

  • limits : 파일 제한
    • fileSize : 파일 사이즈 제한

 

3. multer - 1개 파일 업로드

 

index.js

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const port = 8080;

app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true}));
app.use(express.json());

// 상세 설정 작업
const upload = multer({
    // diskStorage => 하드 디스크에 저장할 때 사용하는 함수
    storage: multer.diskStorage({
        // 저장 경로 설정
        // 폴더도 생성해줘야 한다.
        destination(req, file, done) {
            done(null, 'uploads/');
        },
        // 파일 이름 설정
        filename(req, file, done) {
            console.log(req.body);
            const ext = path.extname(file.originalname);
            // file.originalname => 파일 원래 이름.확장자를 불러옴
            // path.extname() 함수를 이용해서 확장자만 추출 함
            const filename = Date.now() + ext;
            // 날짜 + .확장자 결합
            done(null, filename);
        }
    })
});

app.get('/file', (req, res) => {
    res.render('file2');
});

// 1개 파일을 사용할 때는 single() 함수를 사용한다.
// upload.single('userfile')
// <input type="file" name="userfile"> .single('form 의 name과 같아야 한다')
app.post('/upload', upload.single('userfile'), (req, res) => {
    console.log(req.file);
    console.log(req.body);
    res.send('upload complete');
});
// upload.single() 함수는 multer의 내장 함수로
// 이름을 받아서 업로드까지 하고 next() 함수까지 실행해주는 역할을 한다.
// single() 함수는 1개의 파일만 업로드 할 때 사용한다.

app.listen(port, () => {
    console.log('server open : ', port);
});

 

file2.ejs

<!DOCTYPE html>
<html lang="en, ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>파일 업로드</title>
</head>
<body>
    <h2>업로드</h2>
    <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="userfile">
        <button>업로드</button>
    </form>
</body>
</html>
  • enctype="multipart/form-data"
  • 파일 전송 시 추가 작성 문구, 데이터를 넘겨줄 때 인코딩 작업이 생기는데 해당 문구를 추가하면 파일 업로드 시 인코딩을 하지 않고 전송한다.
  • 인코딩을 하고 파일을 전송하면 파일이 깨진다.

 

실행 결과 - html

실행 결과 - 콘솔 창

실행 결과 - 폴더

 

4. multer - 1개 파일 업로드 + 데이터 전달

 

index.js

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const port = 8080;

app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true}));
app.use(express.json());

// 상세 설정 작업
const upload = multer({
    // diskStorage => 하드 디스크에 저장할 때 사용하는 함수
    storage: multer.diskStorage({
        // 저장 경로 설정
        // 폴더도 생성해줘야 한다.
        destination(req, file, done) {
            done(null, 'uploads/');
        },
        // 파일 이름 설정
        filename(req, file, done) {
            console.log(req.body);
            const ext = path.extname(file.originalname);
            // file.originalname => 파일 원래 이름.확장자를 불러옴
            // path.extname() 함수를 이용해서 확장자만 추출 함
            const filename = Date.now() + ext;
            // 날짜 + .확장자 결합
            done(null, filename);
        }
    })
});


app.get('/file', (req, res) => {
    res.render('file2');
});

// 1개 파일을 사용할 때는 single() 함수를 사용한다.
// upload.single('userfile')
// <input type="file" name="userfile"> .single('form 의 name과 같아야 한다')
app.post('/upload', upload.single('userfile'), (req, res) => {
    console.log(req.file);
    console.log(req.body);
    res.send('upload complete');
});
// upload.single() 함수는 multer의 내장 함수로
// 이름을 받아서 업로드까지 하고 next() 함수까지 실행해주는 역할을 한다.
// single() 함수는 1개의 파일만 업로드 할 때 사용한다.

app.listen(port, () => {
    console.log('server open : ', port);
});

 

file2.ejs

<!DOCTYPE html>
<html lang="en, ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>파일 업로드</title>
</head>
<body>
    <h2>업로드2</h2>
    <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="text" name="name">
        <input type="file" name="userfile">
        <input type="text" name="name2">
        <button>업로드2</button>
    </form>
</body>
</html>

 

실행 결과 - html

실행 결과 - 콘솔 창

실행 결과 - 폴더

 

 

5. multer - 2개 이상 파일 업로드

  • array() : 여러 파일을 업로드할 때 사용, 하나의 요청 안에 여러 개의 파일이 존재할 때

 

index.js

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const port = 8080;

app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true}));
app.use(express.json());

// 상세 설정 작업
const upload = multer({
    // diskStorage => 하드 디스크에 저장할 때 사용하는 함수
    storage: multer.diskStorage({
        // 저장 경로 설정
        // 폴더도 생성해줘야 한다.
        destination(req, file, done) {
            done(null, 'uploads/');
        },
        // 파일 이름 설정
        filename(req, file, done) {
            console.log(req.body);
            const ext = path.extname(file.originalname);
            // file.originalname => 파일 원래 이름.확장자를 불러옴
            // path.extname() 함수를 이용해서 확장자만 추출 함
            const filename = Date.now() + ext;
            // 날짜 + .확장자 결합
            done(null, filename);
        }
    })
});

app.get('/file', (req, res) => {
    res.render('file2');
});

// 2개 이상의 파일을 보내면 array로 받아진다.
// single() 함수 대신에 array 함수를 사용한다.
app.post('/upload-multiple', upload.array('userfile'), (req, res) => {
    // 2개 이상의 파일이기 때문에 req.file이 아닌 req.files로 사용한다.
    console.log(req.files);
    console.log(req.body);
    res.send('upload complete multiple');
});

app.listen(port, () => {
    console.log('server open : ', port);
});

 

file2.ejs

<!DOCTYPE html>
<html lang="en, ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>파일 업로드</title>
</head>
<body>
    <h2>2개 이상 업로드</h2>
    <form action="/upload-multiple" method="post" enctype="multipart/form-data">
        <input type="file" name="userfile" multiple>
        <!-- input에 multiple 속성을 추가하면 2개 이상의 파일 업로드가 가능하다. -->
        <!-- multiple 속성을 주고 파일을 2개 이상 업로드하면 array 형식으로 서버에 보내준다. -->
        <button>2개 이상 업로드</button>
    </form>
</body>
</html>

 

실행 결과 - html

실행 결과 - 콘솔 창

실행 결과 - 폴더

 

7. multer - 1개씩 여러 번의 파일 업로드

  • 1개씩 여러 번의 파일 업로드를 하는 경우 fields() 함수를 사용하며, list - json 방식으로 받는다.
  • fields() : 여러 파일을 업로드할 때 사용, 하나의 요청이 아닌 여러 개의 요청이 들어올 때

 

file2.ejs

<!DOCTYPE html>
<html lang="en, ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>파일 업로드</title>
</head>
<body>
    <h2>1개씩 여러 번 업로드</h2>
    <form action="/upload-fields" method="post" enctype="multipart/form-data">
        <input type="file" name="userfile1">
        <input type="file" name="userfile2">
        <input type="file" name="userfile3">
        <button>1개씩 여러 번 업로드</button>
    </form>
</body>
</html>

 

index.js

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const port = 8080;

app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: true}));
app.use(express.json());

// 상세 설정 작업
const upload = multer({
    // diskStorage => 하드 디스크에 저장할 때 사용하는 함수
    storage: multer.diskStorage({
        // 저장 경로 설정
        // 폴더도 생성해줘야 한다.
        destination(req, file, done) {
            done(null, 'uploads/');
        },
        // 파일 이름 설정
        filename(req, file, done) {
            console.log(req.body);
            const ext = path.extname(file.originalname);
            // file.originalname => 파일 원래 이름.확장자를 불러옴
            // path.extname() 함수를 이용해서 확장자만 추출 함
            const filename = Date.now() + ext;
            // 날짜 + .확장자 결합
            done(null, filename);
        }
    })
});

app.get('/file', (req, res) => {
    res.render('file2');
});

// 1개씩 여러 번의 파일을 업로드하는 경우
// 1개씩 여러번의 파일 업로드를 하는 경우 fields() 함수를 사용하며, list - json 방식으로 받는다.
app.post('/upload-fields', upload.fields([{name: 'userfile1'}, {name: 'userfile2'}, {name: 'userfile3'}]), (req, res) => {
    // 2개 이상의 파일이기 때문에 req.file이 아닌 req.files로 사용한다.
    console.log(req.files);
    console.log(req.body);
    res.send('upload complete fields');
});

app.listen(port, () => {
    console.log('server open : ', port);
});

 

실행 결과 - html

실행 결과 - 콘솔 창

실행 결과 - 폴더

 

 

8. multer의 주의!!!!

multer 사용 시 데이터 전달이 안 되는 경우

 

ex)

. html  or ejs

<input type="text" name="name">
<input type="file" name="userfile">
<input type="text" name="name2"

 

 

-콘솔 창-

[Object: null prototype] { name: '' }
{
    fieldname: 'userfile',
    originalname: 'ani1.gif',
    encoding: '7bit',
    mimetype: 'image/gif',
    destination: 'uploads/',
    filename: '1669435674120.gif',
    path: 'uploads\\1669435674120.gif',
    size: 66300
}
[Object: null prototype] { name: '', name2: '' }

→ name으로 설정한 text의 값은 file 업로드 시 데이터가 같이 전달이 돼서 사용이 가능하지만 name2처럼 type='file' 뒤에 있는 경우에는 데이터가 전달이 되지 않기 때문에 사용이 어렵다.

 

→ 파일과 함께 데이터를 전달하고 싶은 경우에는 type='file' 보다 앞에다가 작성해서 사용하면 된다.

 

-해결 방법- (순서 변경, type=’file’을 제일 뒤로 옮긴다)

<input type="text" name="name">
<input type="text" name="name2"
<input type="file" name="userfile">

 

이상으로 파일 업로드, multer 기능에 대하여 알아보았습니다.

감사합니다.

반응형