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.