Muszę zezwolić użytkownikowi mojej aplikacji na pobranie pliku z Meteorem. Obecnie to, co robię, to kiedy użytkownik żąda pobrania pliku, który wprowadzam do zbioru "fileRequests" w Mongo, dokumentu z lokalizacją pliku i znacznikiem czasu żądania oraz zwraca identyfikator nowo utworzonego żądania. Gdy klient otrzymuje nowy identyfikator, trafia do strony mydomain.com/uploads/id. Następnie używać coś takiego przechwycić żądania przed Meteor robi:Jak używać systemu plików createReadStream z routerem 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();
});
I upewnij się prośba plik powstał mniej niż 5 sekund temu, a ja natychmiast usunąć dokument zapytania po tym jak zapytaliśmy go .
To działa i jest bezpieczne (wystarczy). Nikt nie może złożyć żądania bez zalogowania się, a 5 sekund to bardzo małe okno, aby ktoś mógł przeskoczyć utworzony adres URL żądania, ale po prostu nie czuję się dobrze z moim rozwiązaniem. Czuje się brudno!
Tak więc spróbowałem użyć Meteor-Router, aby osiągnąć to samo. W ten sposób mogę sprawdzić, czy są zalogowani poprawnie, bez 5-sekundowego otwarcia na oszustwo na świecie.
Więc oto kod, który napisałem dla:
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;
}
});
To wygląda świetnie, idealnie wpasowuje się w pozostałej części kodu i jest łatwy do odczytania, nie hacking zaangażowany, ALE! To nie działa! Przeglądarka obraca się i obraca i nigdy nie wie, co robić. Pojawiają się komunikaty o błędach ZERO. Mogę nadal korzystać z aplikacji na innych kartach. Nie wiem, co robi, nigdy nie przestaje "ładować". Jeśli zrestartuję serwer, otrzymam plik 0 bajtów ze wszystkimi poprawnymi nagłówkami, ale nie otrzymam danych.
Każda pomoc jest bardzo ceniona !!
EDIT:
Po wykopaniu się trochę więcej, zauważyłem, że stara się obrócić obiekt odpowiedzi w wynikach obiekt JSON w okrągłym błędu konstrukcji.
Ciekawą rzeczą jest to, że podczas odsłuchiwania strumienia plików dla zdarzenia "data" i próby wiązania obiektu odpowiedzi, nie otrzymuję tego błędu. Ale jeśli spróbuję zrobić to samo w moim pierwszym rozwiązaniu (posłuchaj "danych" i uszereguj odpowiedź), otrzymuję błąd ponownie.
Tak więc przy użyciu rozwiązania Meteor-Router coś dzieje się z obiektem odpowiedzi. Zauważyłem również, że na "danych" wydarzenie response.finished jest oflagowane jako prawdziwe.
filestream.on('data', function(data) {
fs.writeFile('/var/MeteorDMS/afterData', JSON.stringify(res));
});
Mamy ten sam problem. Dowiedzieliśmy się, że są dwa problemy w jednym. Musisz wykonać 'return false;', wywoła to oprogramowanie pośredniczące 'next()' here: https://github.com/tmeasday/meteor-router/blob/master/lib/router_server.js#L86, ale 'pipe() 'nie działa również. Nadal badamy. – nalply