在Node.js中通过HTTP发送大型图像数据

在我的开发环境中,我有两台服务器。 一个通过POST HTTP请求发送和映像到另一个。

客户端服务器这样做:

  fs.readFile(rawFile.path,'binary',function (err, file){ restler.post("http://0.0.0.0:5000",{ data: file, headers:{ "Content-Type": rawFile.type, } }).on('complete',function(data,response){ console.log(data); res.send("file went through") }) 

接收请求的服务器执行以下操作:

  server.post('/',function(req,res,next){ fs.writeFileSync("test.png",req.body,"binary",function(err){ if(err) throw err; res.send("OK") }) }) 

如果我发送一个小图像,它工作正常。 但是,如果我发送一个大的图像,虽然文件保存正确,只有图像的第一个上部分显示。 其余的是黑色的。 图像大小是正确的。

我想这只是正在写入文件的图像的第一个块。 我试过创build一个readStream和一个writeStream但它似乎并没有工作:

 req.body.pipe(fs.createWriteStream('test.png')) 

我可以直接从二进制数据stream并将其传送到文件中吗? 对于我所看到的, readStream通常用于从文件stream而不是原始的二进制数据。

我读了几篇文章,但似乎并没有为我工作。

我正在客户端服务器中使用restler模块,并在另一个。

谢谢!

对不起,生硬,但这里有很多错误。

在调用callbackreadFile将文件的全部内容读入内存,然后开始上传文件。

这很糟糕,特别是在处理像文件这样的大文件时,因为没有理由将文件读入内存。 这是浪费; 并在负载下,你会发现你的服务器将耗尽内存和崩溃。

相反,你想得到一个stream ,当从磁盘读取数据时,它会发出大量的数据。 你所要做的就是把这些块传给你的上传stream( pipe ),然后丢弃内存中的数据。 这样,您永远不会使用超过less量的缓冲区内存。

(可读stream的默认行为是处理原始的二进制数据;只有当您传递了文本中处理的encoding )。

请求模块使这特别容易:

 fs.createReadStream('test.png').pipe(request.post('http://0.0.0.0:5000/')); 

在服务器上,你有一个更大的问题。 切勿使用* Sync方法。 它会阻止服务器执行任何操作 (如响应其他请求),直到整个文件被刷新到磁盘,这可能需要几秒钟的时间。

相反,我们想要将传入的数据stream传送到文件系统stream。 你本来是在正确的轨道上; req.body.pipe(fs.createWriteStream('test.png'))不起作用的原因是body不是stream。

body是由bodyParser中间件生成的。 在restify中,中间件的行为与readFile非常相似,因为它将整个传入的请求实体caching在内存中。 在这种情况下,我们不希望这样做。 禁用身体分析器中间件。

那么传入的数据stream在哪里? 这是req对象本身。 restify的Requestinheritance节点的http.IncomingMessage ,这是一个可读的stream。 所以:

 fs.createWriteStream('test.png').pipe(req); 

我还应该提到,这一切都是如此简单,因为不涉及表单parsing开销。 请求只需发送没有multipart/form-data包装器的文件:

 POST / HTTP/1.1 host: localhost:5000 content-type: application/octet-stream Connection: keep-alive Transfer-Encoding: chunked <image data>... 

这意味着浏览器无法将文件发布到此URL。 如果这是一个需要,看着强大 ,这是stream请求实体的streamparsing。

我不太了解restler。 但发布图像是一个多部分的请求。

 restler.post("http://0.0.0.0:5000",{ data: restler.file(path, filename, fileSize, encoding, contentType), multipart: true }) 

我试过上面的解决scheme,如果你只是移动上传的文件或以下的东西好得多:

fs.rename(path, newPath, callback(err) {});

我上传超过200MB的文件,并会遇到错误使用stream,同步或asynchronous。