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