Creo que si usted quiere hacer el POST, usted tiene que utilizar una Content-Type: multipart/form-data;boundary=myboundary
encabezado. Y luego, en el cuerpo, write()
algo como esto para cada campo de cadena (saltos de línea debe ser \r\n
):
--myboundary
Content-Disposition: form-data; name="field_name"
field_value
y luego por el propio archivo, write()
algo como esto para el cuerpo:
--myboundary
Content-Disposition: form-data; name="file"; filename="urlencoded_filename.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
binary_file_data
El
binary_file_data
es el que utiliza 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");
});
El {end: false}
evita pipe()
para cerrar automáticamente la solicitud porque necesita escribir un límite más después de que haya terminado de enviar el archivo. Tenga en cuenta el --
adicional en el extremo del límite.
El gran problema es que Google puede requerir un encabezado content-length
(muy probable). Si ese es el caso, entonces no puede transmitir un POST de su usuario a un POST a Google porque no sabrá con seguridad qué es el content-length
hasta que haya recibido el archivo completo.
El valor del encabezado content-length
debe ser un número único para todo el cuerpo. La forma más sencilla de hacer esto es llamar al Buffer.byteLength(body)
en todo el cuerpo, pero eso se pone feo rápidamente si tienes archivos grandes y también mata la transmisión.Una alternativa sería calcular que de este modo:
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
embargo, que todavía mata a su capacidad para transmitir desde el usuario al Google, el archivo tiene que ser descargado en el disco local para determinar su longitud.
opción alternativa
... ahora, después de pasar por todo eso, PUT podría ser su amigo. De acuerdo con https://developers.google.com/storage/docs/reference-methods#putobject, puede usar un encabezado transfer-encoding: chunked
, por lo que no necesita encontrar la longitud de los archivos. Y, creo que todo el cuerpo de la solicitud es solo el archivo, por lo que puede usar pipe()
y simplemente dejar que finalice la solicitud cuando esté listo. Si está utilizando https://github.com/felixge/node-formidable para manejar archivos, a continuación, puede hacer algo como esto:
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);
}
}
Desafortunadamente, Google exige que sea una petición POST con el fin de hacer lo que estoy tratando de hacer. Sin embargo, GRAN respuesta, y ciertamente implementaré las sugerencias que hizo. – jwegner
Además, por cierto, node.js le da la capacidad de [detener el proceso de cierre de la conexión] (http://nodejs.org/api/stream.html#stream_stream_pipe_destination_options) – jwegner
Buen punto, me olvidé de eso. Voy a editar la respuesta en caso de que alguien más se encuentre con ella. –