在我的开发环境中,我有两台服务器。一个人通过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")
})
})
如果我发送一个小图像,它可以正常工作。但是,如果我发送大图像虽然文件保存正确,但只显示图像的第一个上半部分。其余的都是黑色的。图像大小正确。
我猜这只是文件中写入的第一块图像。
我尝试创建readStream
和writeStream
,但似乎不起作用:
req.body.pipe(fs.createWriteStream('test.png'))
我可以直接从二进制数据流式传输并将pipe
直接传输到文件中吗?对于我所看到的,readStream
通常用于从文件流而不是原始二进制数据。
我读了一些post但它似乎对我不起作用。
我在客户端服务器中使用restler
模块,在另一个中使用restify
。
谢谢!
答案 0 :(得分:64)
很抱歉直言不讳,但这里有很多错误。
readFile
在调用回调之前将文件的全部内容读入内存,此时您开始上传文件。
这很糟糕 - 特别是在处理像图像这样的大文件时 - 因为没有理由将文件读入内存。这很浪费;在负载下,你会发现你的服务器内存不足并崩溃。
相反,您希望获得流,它会在从磁盘读取数据时发出数据块。您所要做的就是将这些块传递给上传流(pipe
),然后从内存中丢弃数据。这样,你永远不会使用超过少量的缓冲存储器。
(可读流的默认行为是处理原始二进制数据;仅当您传递encoding
时才会处理文本。)
request模块使这一点变得特别简单:
fs.createReadStream('test.png').pipe(request.post('http://0.0.0.0:5000/'));
在服务器上,您遇到了更大的问题。 从不使用* Sync
方法。它阻止您的服务器执行任何(如响应其他请求),直到将整个文件刷新到磁盘,这可能需要秒。
因此,我们希望获取传入的数据流并将其传递给文件系统流。你最初是在正确的轨道上; req.body.pipe(fs.createWriteStream('test.png'))
不起作用的原因是因为body
不是流。
body
由bodyParser
中间件生成。在改进时,该中间件的行为与readFile
非常相似,因为它将整个传入的请求实体缓存在内存中。在这种情况下,我们不希望这样。禁用正文解析器中间件。
那么传入的数据流在哪里?它是req
对象本身。 restify的Request
继承节点的http.IncomingMessage
,这是一个可读的流。所以:
fs.createWriteStream('test.png').pipe(req);
我还应该提一下,这一切都很简单,因为没有形式解析开销。请求只发送没有multipart/form-data
包装器的文件:
POST / HTTP/1.1
host: localhost:5000
content-type: application/octet-stream
Connection: keep-alive
Transfer-Encoding: chunked
<image data>...
这意味着浏览器无法将文件发布到此URL。如果需要,请查看formidable,它会对请求实体进行流解析。
答案 1 :(得分:0)
我对restler知之甚少。但发布图像是一个多部分请求。
restler.post("http://0.0.0.0:5000",{
data: restler.file(path, filename, fileSize, encoding, contentType),
multipart: true
})
答案 2 :(得分:0)
我尝试了上面的解决方案,如果你只是移动上传的文件或其他东西,那么下面的工作会更好:
fs.rename(path, newPath, callback(err) {});
我上传的文件超过200MB,使用流,同步或异步会遇到错误。