在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的Request
inheritance节点的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。