5

ユーザーがファイルを Google Cloud Storage アカウントにアップロードできるようにするアプリを作成しようとしています。上書きを防ぎ、独自の処理とログを作成するために、アップロードの仲介者として Node.js サーバーを使用しています。したがって、プロセスは次のとおりです。

  1. ユーザーがファイルを Node.js サーバーにアップロードする
  2. Node.js サーバーはファイルを解析し、ファイルの種類をチェックし、一部のデータを DB に保存します
  3. Node.js サーバーがファイルを GCS にアップロードする
  4. ユーザーの要求に対する Node.js サーバーの応答と合格/不合格のリマーク

そのファイルをGCSに送信する正確な方法について、ステップ3で少し迷っています。 この質問は、いくつかの役立つ洞察と良い例を提供しますが、私はまだ混乱しています.

ReadStream一時アップロード ファイルの を開き、それをオブジェクトにパイプできることを理解していhttp.request()ます。私が混乱しているのは、パイプされたデータがfile変数であることを POST リクエストでどのように示すかです。GCS API Docsによると、file変数が必要であり、それが最後のものである必要があります。

では、パイプされたデータの POST 変数名を指定するにはどうすればよいでしょうか?

一時ファイルに保存するのではなく、ユーザーのアップロードから直接パイプする方法を教えていただければボーナスポイント

4

1 に答える 1

4

POST を実行する場合は、Content-Type: multipart/form-data;boundary=myboundaryヘッダーを使用する必要があると思います。そして、本文では、write()各文字列フィールドに対して次のようなものがあります (改行は である必要があります\r\n):

--myboundary
Content-Disposition: form-data; name="field_name"

field_value

そして、ファイル自体についてはwrite()、本文に次のようなものがあります。

--myboundary
Content-Disposition: form-data; name="file"; filename="urlencoded_filename.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

binary_file_data

binary_file_data使用する場所は次のpipe()とおりです。

var fileStream = fs.createReadStream("path/to/my/file.jpg");
fileStream.pipe(requestToGoogle, {end: false});
fileStream.on('end, function() {
    req.end("--myboundary--\r\n\r\n");
});

ファイルの送信が完了した後、もう 1 つの境界を書き込む必要があるため、要求が自動的に閉じられるの{end: false}を防ぎます。境界の端にあるpipe()余分な点に注意してください。--

大きな落とし穴は、Google がcontent-lengthヘッダーを必要とする可能性があることです (非常に可能性が高い)。その場合、ユーザーからの POST を POST to Google にストリーミングすることはできませんcontent-length。これは、ファイル全体を受信するまで、何が何であるかを確実に知ることができないためです。

ヘッダーのcontent-length値は、本文全体に対して単一の数値にする必要があります。これを行う簡単な方法は本体全体を呼び出すBuffer.byteLength(body)ことですが、大きなファイルがあるとすぐに見苦しくなりますし、ストリーミングも停止します。別の方法は、次のように計算することです。

var body_before_file = "..."; // string fields + boundary and metadata for the file
var body_after_file = "--myboundary--\r\n\r\n";
var fs = require('fs');
fs.stat(local_path_to_file, function(err, file_info) {
    var content_length = Buffer.byteLength(body_before_file) + 
            file_info.size + 
            Buffer.byteLength(body_after_file);
    // create request to google, write content-length and other headers
    // write() the body_before_file part, 
    // and then pipe the file and end the request like we did above

ただし、それでもユーザーから Google にストリーミングする機能は失われます。ファイルの長さを判断するには、ファイルをローカル ディスクにダウンロードする必要があります。

代替オプション

...さて、これらすべてを経て、PUT があなたの味方になるかもしれません。https://developers.google.com/storage/docs/reference-methods#putobjectによると、ヘッダーを使用できるtransfer-encoding: chunkedため、ファイルの長さを見つける必要はありません。そして、リクエストの本文全体が単なるファイルであると信じているので、使用pipe()して、完了したらリクエストを終了させることができます。https://github.com/felixge/node-formidableを使用してアップロードを処理している場合は、次のようにすることができます。

incomingForm.onPart = function(part) {
    if (part.filename) {
        var req = ... // create a PUT request to google and set the headers
        part.pipe(req);
    } else {
        // let formidable handle all non-file parts
        incomingForm.handlePart(part);
    }
}
于 2012-03-30T21:00:19.380 に答える