Node.js POST文件到服务器

我正在尝试编写一个应用程序,允许我的用户将file upload到我的Google云端存储帐户。 为了防止覆盖,并做一些自定义处理和日志logging,我使用Node.js服务器作为中间人上传。 所以这个过程是:

  1. 用户将file upload到Node.js服务器
  2. Node.js服务器parsing文件,检查文件types,在数据库中存储一些数据
  3. Node.js服务器将file upload到GCS
  4. Node.js服务器响应用户请求的通过/失败备注

我正在步骤3中input一些文件,到底如何把这个文件发送给GCS。 这个问题提供了一些有用的见解,以及一个很好的例子,但我仍然困惑。

我明白,我可以打开一个ReadStream的临时上传文件,并将其传递给http.request()对象。 我感到困惑的是如何在POST请求中表示pipe道数据是filevariables。 根据GCS API Docs ,需要有一个filevariables,它需要是最后一个。

那么,如何为pipe道数据指定一个POSTvariables名呢?

如果您可以告诉我如何直接从我的用户上传pipe道,而不是将其存储在一个临时文件中,奖金点

我相信如果你想做POST,你必须使用Content-Type: multipart/form-data;boundary=myboundary头文件。 然后,在主体中,为每个string字段write()这样的内容(linebreaks应该是\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"); }); 

{end: false}阻止pipe()自动closures请求,因为在完成发送文件之后需要再写一个边界。 注意额外--在边界的末尾。

最大的问题是Google可能需要一个content-length标题(很可能)。 如果是这样的话,那么你不能从你的用户发送一个POST到一个POST到Google,因为在你收到整个文件之前,你不可能知道什么是content-length

content-length标题的值应该是整个主体的单个数字。 这样做的简单方法是调用整个主体上的Buffer.byteLength(body) ,但是如果你有大文件,这会很快变得丑陋,同时也会导致stream式处理。 另一种方法是计算它如下所示:

 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 

但是,这仍然会导致从用户stream向谷歌的能力,文件必须下载到本地磁盘以确定它的长度。

备选选项

…现在,经过这一切,PUT可能是你的朋友在这里。 根据https://developers.google.com/storage/docs/reference-methods#putobject你可以使用transfer-encoding: chunked块头,所以你不需要find文件的长度。 而且,我相信请求的全部内容仅仅是文件,所以你可以使用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); } }