Scarica un file dal server NodeJS utilizzando Express


318

Come posso scaricare un file nel mio server sulla mia macchina accedendo a una pagina in un server nodeJS?

Sto usando ExpressJS e ho provato questo:

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();
});

Ma non riesco a ottenere il nome del file e il tipo di file (o estensione). Qualcuno mi può aiutare con questo?


13
Cordiali saluti. Per l'utilizzo in produzione, è meglio utilizzare node.js dietro nginx e fare in modo che nginx gestisca il contenuto statico. Apparentemente, è molto più adatto a gestirlo.
Munim,

3
I voti
positivi

2
@ user2180794 ma c'è una cosa del genere. Molte altre domande che vengono contrassegnate e votate in basso ne sono la prova. Questa domanda sicuramente non è una però. Corrisponde alle linee guida :)
Assimilater,

La domanda che fai notare è diversa, qui OP vuole restituire un file a un client mentre questa altra domanda riguarda come scaricare un file usando il tuo Nodo del server come client (ad esempio un file di una terza parte). A lesast è quello che ho capito.
Eric Burel,

Risposte:


586

Aggiornare

Express ha un aiuto per rendere la vita più semplice.

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

Vecchia risposta

Per quanto riguarda il tuo browser, il nome del file è solo 'download', quindi devi dargli maggiori informazioni usando un'altra intestazione HTTP.

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

Potresti anche voler inviare un tipo MIME come questo:

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

Se vuoi qualcosa di più approfondito, ecco qui.

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);
});

Puoi impostare il valore dell'intestazione come preferisci. In questo caso, sto usando una libreria di tipo mime - node-mime , per verificare quale sia il tipo di mime del file.

Un'altra cosa importante da notare qui è che ho modificato il codice per utilizzare un readStream. Questo è un modo molto migliore di fare le cose perché l'uso di qualsiasi metodo con "Sync" nel nome è disapprovato perché il nodo deve essere asincrono.


3
Grazie .. C'è un modo per ottenere queste informazioni da fs.readFileSync? Sto usando un file statico in questo esempio, ma userò questa API di download per tutti i file, passandone il nome.
Thiago Miranda de Oliveira,

L'impostazione del nome file di output funziona con res.setHeader('Content-disposition', 'attachment; filename=' + filename);tnx!
Capy,

come scaricare più documenti usando il metodo res.download ().
R J.

1
@RJ. Se hai una domanda, creane una nuova, non lasciare un commento.
loganfsmyth,

7
Express 4.x usa al .set()posto di .setHeader()btw
Dana Woodman

48

Uso res.download()

Trasferisce il file sul percorso come "allegato". Per esempio:

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
Cosa succede se i dati provengono da una richiesta HTTP anziché da un file e dobbiamo consentire agli utenti di scaricare il file in modo streaming?
summerNight

1
@summerNight - beh, questo è un caso diverso rispetto alla domanda specificata. cercare le nodejs proxy file download responsemigliori pratiche
Jossef Harush,

15

Per file statici come pdf, documenti Word, ecc. Basta usare la funzione statica di Express nella configurazione:

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

E quindi inserisci tutti i tuoi file in quella cartella "pubblica", ad esempio:

/public/docs/my_word_doc.docx

E quindi un vecchio link regolare consentirà all'utente di scaricarlo:

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

1
Funziona bene per le risorse (anche se si consiglia un proxy di servizio dedicato come nginx). Ma per tutto ciò che richiede un accesso sicuro, il metodo accettato è migliore. In generale, per documenti e file contenenti informazioni, non consiglierei l'uso del metodo pubblico.
nembleton,

1
è possibile aggiungere middleware per garantire che solo gli utenti appropriati possano accedere ai file
MalcolmOcean

1
ad es. this.use('/topsecret', mGetLoggedInUser, mEnsureAccess, express.static('topsecret'))... e quindi ogni richiesta passa attraverso mEnsureAccess. Ovviamente, ciò significa che dovrai essere in grado di capire il livello di accesso di un utente solo in base all'URL del documento protetto o altro.
MalcolmOcean

14

In Express 4.x esiste un attachment()metodo per 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

Ecco come lo faccio:

  1. crea file
  2. invia il file al client
  3. Rimuovi il file

Codice:

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
questa è l'unica soluzione che ho trovato in circa due giorni di ricerche che funziona per il mio particolare scenario di ottenere un file audio. l'unica cosa è che non credo res.download () funziona con $ .ajax chiamate purtroppo - ho dovuto usare window.open("/api/get_audio_file");, vedere: stackoverflow.com/a/20177012
user1063287
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.