Expressを使用してNodeJS Serverからファイルをダウンロードする


318

サーバーにあるファイルを、nodeJSサーバーのページにアクセスするマシンにダウンロードするにはどうすればよいですか?

私はExpressJSを使用していますが、これを試しています:

app.get('/download', function(req, res){

  var file = fs.readFileSync(__dirname + '/upload-folder/dramaticpenguin.MOV', 'binary');

  res.setHeader('Content-Length', file.length);
  res.write(file, 'binary');
  res.end();
});

しかし、ファイル名とファイルタイプ(または拡張子)を取得できません。誰かが私を助けてくれますか?


13
参考までに。本番環境で使用するには、nginxの背後でnode.jsを使用し、nginxで静的コンテンツを処理することをお勧めします。どうやら、それを処理するのにはるかに適しています。
Munim

3
賛成票は、馬鹿げた質問などないことを証明します:)
user2180794

2
@ user2180794でもそんなことがある。フラグが立てられ、反対票が投じられる他の多くの質問は、その証拠です。この質問は確かに1つではありません。それはガイドラインと一致します:)
Assimilater

あなたが指摘する質問は異なります。ここでOPはファイルをクライアントに返したいのに対して、この別の質問はサーバーノードをクライアントとして使用してファイルをダウンロードする方法に関するものです(たとえば、サードパーティからのファイル)。少なくとも、それは私が理解したことです。
エリックバレル2018年

回答:


586

更新

Expressには、これを容易にするためのヘルパーがあります。

app.get('/download', function(req, res){
  const file = `${__dirname}/upload-folder/dramaticpenguin.MOV`;
  res.download(file); // Set disposition and send it.
});

古い答え

ブラウザに関する限り、ファイルの名前は単に「ダウンロード」であるため、別のHTTPヘッダーを使用して詳細情報を提供する必要があります。

res.setHeader('Content-disposition', 'attachment; filename=dramaticpenguin.MOV');

次のようなMIMEタイプを送信することもできます。

res.setHeader('Content-type', 'video/quicktime');

より詳細な情報が必要な場合は、こちらにアクセスしてください。

var path = require('path');
var mime = require('mime');
var fs = require('fs');

app.get('/download', function(req, res){

  var file = __dirname + '/upload-folder/dramaticpenguin.MOV';

  var filename = path.basename(file);
  var mimetype = mime.lookup(file);

  res.setHeader('Content-disposition', 'attachment; filename=' + filename);
  res.setHeader('Content-type', mimetype);

  var filestream = fs.createReadStream(file);
  filestream.pipe(res);
});

ヘッダー値は好きなように設定できます。この場合、私は、MIMEタイプライブラリを使用しています- ノード・パントマイムを、ファイルのMIMEタイプが何であるかをチェックします。

ここでもう1つ重要なのは、readStreamを使用するようにコードを変更したことです。ノードが非同期であることを意図しているため、名前に 'Sync'を含むメソッドを使用することは好ましくないため、これはより良い方法です。


3
ありがとう.. fs.readFileSyncからこの情報を取得する方法はありますか?この例では静的ファイルを使用していますが、ファイルの名前を渡してすべてのファイルにこのダウンロードAPIを使用します。
チアゴミランダデオリベイラ

出力ファイル名の設定はres.setHeader('Content-disposition', 'attachment; filename=' + filename);tnxで機能します!
Capy

res.download()メソッドを使用して複数のドキュメントをダウンロードする方法。
R J.

1
@RJ。質問がある場合は、新しい質問を作成し、コメントを残さないでください。
loganfsmyth 2013

7
Express 4.xはbtwの.set()代わりに使用する.setHeader()
Dana Woodman

48

使用する res.download()

パスにあるファイルを「添付ファイル」として転送します。例えば:

var express = require('express');
var router = express.Router();

// ...

router.get('/:id/download', function (req, res, next) {
    var filePath = "/my/file/path/..."; // Or format the path using the `id` rest param
    var fileName = "report.pdf"; // The default name the browser will use

    res.download(filePath, fileName);    
});

6
データがファイルではなくHTTPリクエストから送信され、ユーザーがストリーミングでファイルをダウンロードできるようにする必要がある場合はどうなりますか?
summerNight 2017

1
@summerNight-まあ、それは指定された質問とは異なるケースです。nodejs proxy file download responseベストプラクティスを検索
ジョセフハルシュ

15

PDF、Wordドキュメントなどの静的ファイルの場合は、設定でExpressの静的関数を使用します。

// Express config
var app = express().configure(function () {
    this.use('/public', express.static('public')); // <-- This right here
});

次に、すべてのファイルを「public」フォルダに入れます。次に例を示します。

/public/docs/my_word_doc.docx

そして、通常の古いリンクはユーザーがそれをダウンロードできるようにします:

<a href="public/docs/my_word_doc.docx">My Word Doc</a>

1
これはアセットに適しています(nginxのような専用のサービングプロキシが推奨されます)。ただし、セキュリティで保護されたアクセスが必要な場合は、受け入れられている方法の方が適しています。一般的に、情報を含むドキュメントとファイルについては、パブリックメソッドの使用はお勧めしません。
nembleton 2015年

1
適切なユーザーだけがファイルにアクセスできるようにするミドルウェアを追加できます
MalcolmOcean

1
たとえばthis.use('/topsecret', mGetLoggedInUser, mEnsureAccess, express.static('topsecret'))...そして、各リクエストはmEnsureAccessを通過します。もちろん、これは、セキュリティで保護されたドキュメントのURLなどに基づいて、ユーザーのアクセスレベルを把握できる必要があることを意味します。
MalcolmOcean

14

Express 4.xには、次のattachment()方法がありResponseます。

res.attachment();
// Content-Disposition: attachment

res.attachment('path/to/logo.png');
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png

6
'use strict';

var express = require('express');
var fs = require('fs');
var compress = require('compression');
var bodyParser = require('body-parser');

var app = express();
app.set('port', 9999);
app.use(bodyParser.json({ limit: '1mb' }));
app.use(compress());

app.use(function (req, res, next) {
    req.setTimeout(3600000)
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept,' + Object.keys(req.headers).join());

    if (req.method === 'OPTIONS') {
        res.write(':)');
        res.end();
    } else next();
});

function readApp(req,res) {
  var file = req.originalUrl == "/read-android" ? "Android.apk" : "Ios.ipa",
      filePath = "/home/sony/Documents/docs/";
  fs.exists(filePath, function(exists){
      if (exists) {     
        res.writeHead(200, {
          "Content-Type": "application/octet-stream",
          "Content-Disposition" : "attachment; filename=" + file});
        fs.createReadStream(filePath + file).pipe(res);
      } else {
        res.writeHead(400, {"Content-Type": "text/plain"});
        res.end("ERROR File does NOT Exists.ipa");
      }
    });  
}

app.get('/read-android', function(req, res) {
    var u = {"originalUrl":req.originalUrl};
    readApp(u,res) 
});

app.get('/read-ios', function(req, res) {
    var u = {"originalUrl":req.originalUrl};
    readApp(u,res) 
});

var server = app.listen(app.get('port'), function() {
    console.log('Express server listening on port ' + server.address().port);
});

5

ここに私がそれをする方法があります:

  1. ファイルを作成する
  2. クライアントにファイルを送信
  3. ファイルを削除

コード:

let fs = require('fs');
let path = require('path');

let myController = (req, res) => {
  let filename = 'myFile.ext';
  let absPath = path.join(__dirname, '/my_files/', filename);
  let relPath = path.join('./my_files', filename); // path relative to server root

  fs.writeFile(relPath, 'File content', (err) => {
    if (err) {
      console.log(err);
    }
    res.download(absPath, (err) => {
      if (err) {
        console.log(err);
      }
      fs.unlink(relPath, (err) => {
        if (err) {
          console.log(err);
        }
        console.log('FILE [' + filename + '] REMOVED!');
      });
    });
  });
};

2
これは、オーディオファイルを取得するという私の特定のシナリオで機能する、約2日間の検索で見つけた唯一のソリューションです。唯一のことは、私は考えていないということです)res.download(で動作します$アヤックス私が使用していた-残念ながら通話window.open("/api/get_audio_file");:、参照 stackoverflow.com/a/20177012
user1063287
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.