안녕하세요.
이번엔 Node.js Express에서 파일을 다운로드하는 기능을 구현해보겠습니다.
먼저 아래와 같이 필요한 모듈을 설치해줍니다.
npm i mime
그 다음 다운로드 라우터를 따로 만들어 주시고 아래와 같이 작성해주세요.
var express = require('express');
var router = express.Router();
var fs = require('fs');
var path = require('path');
var mime = require('mime');
router.get('/:file_name', function(req, res, next) {
var upload_folder = '업로드 폴더 경로';
var file = upload_folder + req.params.file_name; // ex) /upload/files/sample.txt
try {
if (fs.existsSync(file)) { // 파일이 존재하는지 체크
var filename = path.basename(file); // 파일 경로에서 파일명(확장자포함)만 추출
var mimetype = mime.getType(file); // 파일의 타입(형식)을 가져옴
res.setHeader('Content-disposition', 'attachment; filename=' + filename); // 다운받아질 파일명 설정
res.setHeader('Content-type', mimetype); // 파일 형식 지정
var filestream = fs.createReadStream(file);
filestream.pipe(res);
} else {
res.send('해당 파일이 없습니다.');
return;
}
} catch (e) { // 에러 발생시
console.log(e);
res.send('파일을 다운로드하는 중에 에러가 발생하였습니다.');
return;
}
});
module.exports = router;
그리고 테스트 해보시면 정상적으로 다운로드가 되실 겁니다.
하지만 여기서 문제가 하나 생깁니다. 파일명에 한글이 포함되어 있으면
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
부분에서 에러가 발생합니다.
해당 에러를 해결하기 위해선 아래와 같이 작업합니다..
먼저, 필요한 모듈을 설치합니다.
npm i iconv-lite
그리고 다운로드 라우터 파일과 동일한 경로에 lib 라는 폴더를 생성하고
이 폴더에 getDownloadFilename.js 라는 파일을 생성 후 아래와 같이 작성해줍니다.
var iconvLite = require('iconv-lite');
module.exports = {
getDownloadFilename: function(req, filename) {
var header = req.headers['user-agent'];
if (header.includes("MSIE") || header.includes("Trident")) {
return encodeURIComponent(filename).replace(/\\+/gi, "%20");
} else if (header.includes("Chrome")) {
return iconvLite.decode(iconvLite.encode(filename, "UTF-8"), 'ISO-8859-1');
} else if (header.includes("Opera")) {
return iconvLite.decode(iconvLite.encode(filename, "UTF-8"), 'ISO-8859-1');
} else if (header.includes("Firefox")) {
return iconvLite.decode(iconvLite.encode(filename, "UTF-8"), 'ISO-8859-1');
}
return filename;
}
};
그리고 다운로드 라우터를 아래와 같이 수정합니다.
var express = require('express');
var router = express.Router();
var fs = require('fs');
var path = require('path');
var mime = require('mime');
var getDownloadFilename = require('./library/getDownloadFilename').getDownloadFilename;
router.get('/:file_name', function(req, res, next) {
var upload_folder = '업로드 폴더 경로';
var file = upload_folder + req.params.file_name; // ex) /upload/files/sample.txt
try {
if (fs.existsSync(file)) { // 파일이 존재하는지 체크
var filename = path.basename(file); // 파일 경로에서 파일명(확장자포함)만 추출
var mimetype = mime.getType(file); // 파일의 타입(형식)을 가져옴
res.setHeader('Content-disposition', 'attachment; filename=' + getDownloadFilename(req, filename)); // 다운받아질 파일명 설정
res.setHeader('Content-type', mimetype); // 파일 형식 지정
var filestream = fs.createReadStream(file);
filestream.pipe(res);
} else {
res.send('해당 파일이 없습니다.');
return;
}
} catch (e) { // 에러 발생시
console.log(e);
res.send('파일을 다운로드하는 중에 에러가 발생하였습니다.');
return;
}
});
module.exports = router;
아까 작성한 다운로드 라우터 파일에서 조금 수정되었습니다.
이제 파일명에 한글이 포함되어도 정상적으로 다운로드 가능해졌습니다.
궁금하신 점 있으면 댓글 남겨주세요!
※ 잘못된 정보가 있으면 알려주세요.