2013-06-12 7 views
5

私のアプリのユーザーがMeteorでファイルをダウンロードできるようにする必要があります。現在私がやっているのは、ユーザーがファイルのダウンロードをリクエストしたときです。ファイルの場所とリクエストのタイムスタンプを持つドキュメントをMongoの "fileRequests"コレクションに入れ、新しく作成したリクエストのIDを返します。クライアントが新しいIDを取得すると、すぐにmydomain.com/uploads/:idに行きます。流星が行う前に、私はその要求を傍受するために、このようなものを使用します。Meteor router(NodeJS)でファイルシステムのcreateReadStreamを使用する方法

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

、右のコードの残りの部分とに収まると、何が関与ハッキング読まないのは簡単ですが、!それは動作しません!ブラウザは回転して回転し、何をすべきか分かりません。私はゼロエラーメッセージが表示されます。私は他のタブでアプリを使い続けることができます。私はそれが何をしているのかわからない、それは決して "ロード"を停止しません。サーバーを再起動すると、すべての正しいヘッダーを含む0バイトのファイルが取得されますが、データは取得されません。

何か助けていただければ幸いです。

EDIT:

より少し周り掘り後、私は円形構造エラーにJSONオブジェクトの結果に応答オブジェクトを有効にしようとしていることに気づきました。

ここで興味深いのは、 "データ"イベントのファイルストリームを聞いて、応答オブジェクトを文字列化しようとすると、そのエラーが発生しないということです。しかし、私が最初の解決策( "データ"を聞いて、応答を文字列化する)で同じことをしようとすると、再びエラーが発生します。

したがって、Meteor-Routerソリューションを使用すると、応答オブジェクトに何かが起こっています。私はまた、 "データ"イベントのresponse.finishedにtrueとフラグが立てられていることに気付きました。

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

。私たちは1つには2つの問題があることを知りました。 'return false;'を実行する必要があります。これはhttps://github.com/tmeasday/meteor-router/blob/master/lib/router_server.js#L86でミドルウェアの 'next()'を呼び出しますが、 'pipe () 'も動作しません。私たちはまだ調査中です。 – nalply

答えて

1

メテオルーダはルーティングを行うミドルウェアをインストールします。すべてのConnectミドルウェアはnext()(正確に1回)を呼び出して、応答がまだ解決されていないことを示すか、またはres.end()を呼び出すか、応答にパイプすることによって応答を解決する必要があります。両方を行うことはできません。

私はミドルウェアのソースコードを調べました(下記参照)。我々はfalseを返してnext()に電話するようミドルウェアに伝えることができることがわかります。これは、このルートが応答を解決しなかったと宣言し、他のミドルウェアにその作業をさせたいということを意味します。

それとも、テキスト、配列[status, text]または配列[status, headers, text]をテンプレート名を返すことができ、およびミドルウェアは、我々が返されたデータを使用してres.end()を呼び出すことにより、当社に代わって応答を解決します。

しかし、応答にパイプすることで、私たちはすでに応答を解決しました。流星のルータはnext()またはres.end()を呼ぶべきではありません。

メテオのルーターを作り、小さな変更を加えることで問題を解決しました。我々はによって(if (output === false)後)ライン87に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

関連する問題