Tôi tin rằng nếu bạn muốn làm POST, bạn phải sử dụng một tiêu đề. Và sau đó, trong cơ thể, write()
một cái gì đó như thế này đối với từng lĩnh vực chuỗi (linebreaks nên \r\n
):
--myboundary
Content-Disposition: form-data; name="field_name"
field_value
và sau đó cho các tập tin bản thân, write()
một cái gì đó như thế này để cơ thể:
--myboundary
Content-Disposition: form-data; name="file"; filename="urlencoded_filename.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
binary_file_data
Các binary_file_data
là nơi bạn sử dụng 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");
});
Các {end: false}
ngăn pipe()
tự động đóng yêu cầu vì bạn cần phải viết thêm một đường biên sau khi bạn gửi xong tệp. Lưu ý thêm --
ở cuối ranh giới.
Bí quyết lớn là Google có thể yêu cầu tiêu đề content-length
(rất có thể). Nếu đúng như vậy, bạn không thể truyền một POST từ người dùng của mình tới POST tới Google vì bạn sẽ không biết chắc chắn những gì mà content-length
là cho đến khi bạn nhận được toàn bộ tệp.
Giá trị của tiêu đề content-length
phải là một số duy nhất cho toàn bộ phần thân. Cách đơn giản để thực hiện việc này là gọi số Buffer.byteLength(body)
trên toàn bộ cơ thể, nhưng điều đó sẽ trở nên xấu xí nhanh chóng nếu bạn có các tệp lớn và nó cũng sẽ tiêu diệt luồng.Một giải pháp thay thế sẽ là tính toán như sau:
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
Tuy nhiên, vẫn có thể tải xuống đĩa địa phương để xác định độ dài của tệp.
lựa chọn thay thế
... bây giờ, sau khi vượt qua tất cả điều đó, PUT có thể là bạn của bạn ở đây. Theo số https://developers.google.com/storage/docs/reference-methods#putobject, bạn có thể sử dụng tiêu đề transfer-encoding: chunked
để bạn không cần tìm chiều dài tệp. Và, tôi tin rằng toàn bộ cơ thể của yêu cầu chỉ là tệp, vì vậy bạn có thể sử dụng pipe()
và chỉ để cho nó kết thúc yêu cầu khi nó được thực hiện. Nếu bạn đang sử dụng https://github.com/felixge/node-formidable để xử lý video tải lên, thì bạn có thể làm điều gì đó như sau:
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);
}
}
Thật không may, Google yêu cầu nó là yêu cầu POST để làm những gì tôi đang cố gắng làm. Tuy nhiên, câu trả lời tuyệt vời, và tôi chắc chắn sẽ thực hiện các đề xuất bạn đã thực hiện. – jwegner
Ngoài ra, bằng cách này, node.js cung cấp cho bạn khả năng [dừng đường ống từ việc đóng kết nối] (http://nodejs.org/api/stream.html#stream_stream_pipe_destination_options) – jwegner
Điểm tốt, tôi quên mất điều đó. Tôi sẽ chỉnh sửa câu trả lời trong trường hợp bất kỳ ai khác bắt gặp nó. –