본문 바로가기

Node.js

Node.js Express 파일 다운로드 구현

안녕하세요. 

 

이번엔 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;

아까 작성한 다운로드 라우터 파일에서 조금 수정되었습니다.

이제 파일명에 한글이 포함되어도 정상적으로 다운로드 가능해졌습니다.

 

궁금하신 점 있으면 댓글 남겨주세요!

 

 

※ 잘못된 정보가 있으면 알려주세요.