2013-06-12 84 views
5

我需要允許我的應用程序的用戶使用Meteor下載文件。目前我所做的是當用戶請求下載我在Mongo的「fileRequests」集合中輸入的文件時,該文件包含文件位置和請求的時間戳,並返回新創建的請求的ID。當客戶端獲得新的ID時,它立即進入mydomain.com/uploads/:id。然後,我使用這樣的攔截請求流星不前:如何使用Meteor路由器的文件系統的createReadStream(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(); 
    }); 

我檢查,以確保文件的請求,不到5秒鐘前做的,我立即刪除請求的文檔,我查詢後。

這是有效的,我認爲是安全的(足夠)。沒有人可以在沒有登錄的情況下提出請求,5秒對於某人能夠強制創建請求URL而言是一個非常小的窗口,但我對我的解決方案感到不滿。感覺很髒!

所以我試圖用Meteor-Router來完成同樣的事情。這樣,我可以檢查他們是否正確登錄,而不會對世界做出5秒的欺騙。

因此,這裏是我寫的代碼:

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

這看起來不錯,正適合你的代碼的其餘部分,易於閱讀,無盜號受累,但!它不起作用!瀏覽器旋轉並旋轉,從不知道該怎麼做。我有ZERO錯誤消息出現。我可以繼續在其他選項卡上使用該應用程序。我不知道它在做什麼,它永遠不會停止「加載」。如果我重新啓動服務器,我會得到一個包含所有正確標題的0字節文件,但我沒有收到數據。

任何幫助非常感謝!

編輯:

周圍略偏挖後,我注意到,試圖把響應對象成圓形結構誤差JSON對象的結果。

現在有趣的是,當我爲「數據」事件監聽文件流,並嘗試對響應對象進行字符串化處理時,我不會收到該錯誤。但是,如果我嘗試在我的第一個解決方案中執行相同的操作(監聽「數據」並將響應字符串化),則會再次出現錯誤。

因此,使用Meteor-Router解決方案響應對象正在發生一些事情。我還注意到,在「數據」事件response.finished被標記爲true。

filestream.on('data', function(data) { 
    fs.writeFile('/var/MeteorDMS/afterData', JSON.stringify(res)); 
}); 
+0

我們有同樣的問題。我們發現其中一個存在兩個問題。你需要做'return false;',這裏調用中間件的'next()':https://github.com/tmeasday/meteor-router/blob/master/lib/router_server.js#L86,但是'pipe ()'也不起作用。我們仍在調查。 – nalply

回答

1

Meteor路由器安裝一箇中間件來完成路由。所有連接中間件都必須調用next()(恰好一次)來表明響應尚未結算,或者必須通過調用res.end()或通過管道響應來解決響應。這是不允許的。

我研究了中間件的源代碼(見下文)。我們看到,我們可以返回false告訴中間件請致電next()。這意味着我們宣佈這條路線並未解決問題,我們希望讓其他中間件完成他們的工作。

或者,我們可以返回一個模板名稱,文本,數組[status, text]或數組[status, headers, text],並且中間件將通過使用我們返回的數據調用res.end()解決代表我們的響應。

但是,通過響應,我們已經解決了響應。 Meteor路由器不應該撥打next()也不要撥打res.end()

我們通過分流Meteor路由器並做了一些小改動來解決了這個問題。我們替換線87(if (output === false)後)else方式:

else if (typeof(output)!="undefined") { 

請參閱在我的叉子SHA 8d8fc23d9c提交。

這樣路線方法return;會告訴路由器做沒有什麼。當然你已經通過管道來解決這個問題。中間件作爲


的源代碼提交與SHA f910a090ae

// hook up the serving 
__meteor_bootstrap__.app 
    .use(connect.query()) // <- XXX: we can probably assume accounts did this 
    .use(this._config.requestParser(this._config.bodyParser)) 
    .use(function(req, res, next) { 
    // need to wrap in a fiber in case they do something async 
    // (e.g. in the database) 
    if(typeof(Fiber)=="undefined") Fiber = Npm.require('fibers'); 

    Fiber(function() { 
     var output = Meteor.Router.match(req, res); 

     if (output === false) { 
     return next(); 
     } else { 
     // parse out the various type of response we can have 

     // array can be 
     // [content], [status, content], [status, headers, content] 
     if (_.isArray(output)) { 
      // copy the array so we aren't actually modifying it! 
      output = output.slice(0); 

      if (output.length === 3) { 
      var headers = output.splice(1, 1)[0]; 
      _.each(headers, function(value, key) { 
       res.setHeader(key, value); 
      }); 
      } 

      if (output.length === 2) { 
      res.statusCode = output.shift(); 
      } 

      output = output[0]; 
     } 

     if (_.isNumber(output)) { 
      res.statusCode = output; 
      output = ''; 
     } 

     return res.end(output); 
     } 
    }).run(); 
    }); 
+0

**注意**:與此同時,Meteor 6.5已經不存在了,我更換的路由器不再工作了。 – nalply

相關問題