29

私の開発環境には、2 つのサーバーがあります。POST一方はhttp 要求を介して他方に画像を送信します。

クライアントサーバーはこれを行います:

    fs.readFile(rawFile.path,'binary',function (err, file){
        restler.post("http://0.0.0.0:5000",{
            data: file,
            headers:{
                "Content-Type": rawFile.type,
            }
        }).on('complete',function(data,response){                               
            console.log(data);
            res.send("file went through")
        })

リクエストを受信したサーバーは次のことを行います。

    server.post('/',function(req,res,next){
        fs.writeFileSync("test.png",req.body,"binary",function(err){
            if(err) throw err;
            res.send("OK")
        })
    })

小さな画像を送信すると、正常に機能します。ただし、ファイルが正しく保存されているにもかかわらず、大きな画像を送信すると、画像の最初の上部のみが表示されます。残りは黒です。画像サイズは正しいです。

ファイルに書き込まれているのは、画像の最初のチャンクにすぎないと思います。readStreamaと aを作成しようとしましたwriteStreamが、うまくいかないようです:

req.body.pipe(fs.createWriteStream('test.png'))

バイナリ データから直接ストリーミングしpipeて、ファイルに入れることはできますか? 私が見たものについては、readStream生のバイナリデータではなくファイルからストリーミングするためによく使用されます。

いくつかの投稿を読みましたが、うまくいかないようです。

restlerクライアントサーバーと他のサーバーでモジュールを使用していますrestify

ありがとう!

4

3 に答える 3

69

率直に言って申し訳ありませんが、ここには多くの間違いがあります。

readFileコールバックを呼び出す前に、ファイルの内容全体をメモリに読み込みます。コールバックを呼び出すと、ファイルのアップロードが開始されます。

これは悪いことです。特に画像のような大きなファイルを扱う場合は、ファイルをメモリに読み込む理由が実際にはないためです。それは無駄です。負荷がかかると、サーバーのメモリが不足してクラッシュすることがわかります。

代わりに、ディスクから読み取られるときにデータのチャンクを放出するストリームを取得する必要があります。あなたがしなければならないのは、それらのチャンクをアップロードストリーム(pipe)に渡してから、メモリからデータを破棄することです。このようにして、少量以上のバッファメモリを使用することはありません。

encoding(読み取り可能なストリームのデフォルトの動作は、生のバイナリデータを処理することです。テキストで処理するのは、渡した場合のみです。)

リクエストモジュールを使用すると、これが特に簡単になります。

fs.createReadStream('test.png').pipe(request.post('http://0.0.0.0:5000/'));

サーバーでは、より大きな問題があります。 *Syncメソッドは絶対に使用しないでください。 ファイル全体がディスクにフラッシュされるまで、サーバーは何も実行できなくなります(他の要求への応答など)。これには数秒かかる場合があります。

したがって、代わりに、着信データストリームを取得し、それをファイルシステムストリームにパイプします。あなたはもともと正しい方向に進んでいました。req.body.pipe(fs.createWriteStream('test.png'))動作しなかった理由bodyは、ストリームではないためです。

bodybodyParserミドルウェアによって生成されます。言い換えると、そのミドルウェアはreadFile、着信要求エンティティ全体をメモリにバッファリングするという点で非常によく似ています。この場合、それは望ましくありません。ボディパーサーミドルウェアを無効にします。

では、着信データストリームはどこにありますか?それはreqオブジェクトそのものです。restifyは、読み取り可能なストリームであるRequestノードを継承します。http.IncomingMessageそれで:

fs.createWriteStream('test.png').pipe(req);

また、フォーム解析のオーバーヘッドが含まれていないため、これはすべて非常にうまく機能することにも言及する必要があります。requestは、multipart/form-dataラッパーなしでファイルを送信するだけです。

POST / HTTP/1.1
host: localhost:5000
content-type: application/octet-stream
Connection: keep-alive
Transfer-Encoding: chunked

<image data>...

これは、ブラウザがこのURLにファイルを投稿できなかったことを意味します。それが必要な場合は、リクエストエンティティのストリーミング解析を行う手ごわいものを調べてください。

于 2013-02-21T16:58:17.137 に答える
0

上記の解決策を試しましたが、アップロードされたファイルなどを移動しただけの場合は、次の方法がはるかにうまく機能します。

fs.rename(path, newPath, callback(err) {});

200MB を超えるファイルをアップロードしていましたが、ストリーム、同期、または非同期を使用してエラーが発生しました。

于 2013-09-06T18:38:00.790 に答える
0

私はレストラーについてあまり知りません。ただし、画像の投稿はマルチパート リクエストです。

restler.post("http://0.0.0.0:5000",{
    data: restler.file(path, filename, fileSize, encoding, contentType),
    multipart: true
})
于 2013-02-21T12:15:31.650 に答える