Devo consentire all'utente della mia app di scaricare un file con Meteor. Attualmente quello che faccio è quando l'utente richiede di scaricare un file che inserisco in una raccolta "fileRequests" in Mongo un documento con il percorso del file e un timestamp della richiesta e restituire l'ID della richiesta appena creata. Quando il cliente riceve il nuovo ID, passa immediatamente a mydomain.com/uploads/:id. Ho quindi utilizzare qualcosa di simile per intercettare la richiesta prima Meteor fa:Come utilizzare createReadStream di filesystem con il router Meteor (NodeJS)
var connect = Npm.require("connect");
var Fiber = Npm.require("fibers");
var path = Npm.require('path');
var fs = Npm.require("fs");
var mime = Npm.require("mime");
__meteor_bootstrap__.app
.use(connect.query())
.use(connect.bodyParser()) //I add this for file-uploading
.use(function (req, res, next) {
Fiber(function() {
if(req.method == "GET") {
// get the id here, and stream the file using fs.createReadStream();
}
next();
}).run();
});
Posso controllare per assicurarsi che il file di richiesta è stata fatta meno di 5 secondi fa, e ho subito cancellare il documento di richiesta dopo che ho interrogato esso .
Questo funziona, ed è sicuro (abbastanza) penso. Nessuno può effettuare una richiesta senza aver effettuato l'accesso e 5 secondi è una finestra piuttosto piccola per consentire a qualcuno di essere in grado di bloccare l'URL della richiesta creata ma semplicemente non mi sento a posto con la mia soluzione. Sembra sporco!
Quindi ho tentato di utilizzare Meteor-Router per eseguire la stessa operazione. In questo modo posso controllare se sono loggati correttamente senza fare il 5 secondo aperto agli inganni mondiali.
Quindi, ecco il codice che ho scritto per questo:
Meteor.Router.add('/uploads/:id', function(id) {
var path = Npm.require('path');
var fs = Npm.require("fs");
var mime = Npm.require("mime");
var res = this.response;
var file = FileSystem.findOne({ _id: id });
if(typeof file !== "undefined") {
var filename = path.basename(file.filePath);
var filePath = '/var/MeteorDMS/uploads/' + filename;
var stat = fs.statSync(filePath);
res.setHeader('Content-Disposition', 'attachment; filename=' + filename);
res.setHeader('Content-Type', mime.lookup(filePath));
res.setHeader('Content-Length', stat.size);
var filestream = fs.createReadStream(filePath);
filestream.pipe(res);
return;
}
});
Questo sembra grande, si adatta a destra dentro con il resto del codice ed è di facile lettura, senza l'hacking coinvolto, MA! Non funziona! Il browser gira e gira e non sa mai cosa fare. Ho dei messaggi di errore ZERO in arrivo. Posso continuare a utilizzare l'app su altre schede. Non so cosa stia facendo, non si ferma mai "in caricamento". Se riavvio il server, ottengo un file da 0 byte con tutte le intestazioni corrette, ma non ottengo i dati.
Qualsiasi aiuto è molto apprezzato !!
EDIT:
Dopo scavato un po 'di più, ho notato che cercando di trasformare l'oggetto risposta in un oggetto JSON generato un errore struttura circolare.
Ora la cosa interessante di questo è che quando ascolto il filestream per l'evento "dati" e provo a stringificare l'oggetto risposta, non ottengo quell'errore. Ma se provo a fare la stessa cosa nella mia prima soluzione (ascoltare "dati" e stringificare la risposta) ottengo di nuovo l'errore.
Così utilizzando la soluzione Meteor-Router qualcosa sta accadendo all'oggetto risposta. Ho anche notato che sull'evento "data" response.finished è contrassegnato come true.
filestream.on('data', function(data) {
fs.writeFile('/var/MeteorDMS/afterData', JSON.stringify(res));
});
Abbiamo lo stesso problema. Abbiamo scoperto che ci sono due problemi in uno. Devi fare 'return false;', questo richiama il middleware 'next()' qui: https://github.com/tmeasday/meteor-router/blob/master/lib/router_server.js#L86, ma 'pipe() 'non funziona, anche. Stiamo ancora indagando. – nalply