在我的开发环境中,我有两个服务器。一个通过POSThttp请求将图像发送给另一个。
POST
客户端服务器执行以下操作:
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但似乎不起作用:
readStream
writeStream
req.body.pipe(fs.createWriteStream('test.png'))
我可以直接从二进制数据流传输pipe到文件吗?对于我所看到的,readStream通常用于从文件而不是原始二进制数据流。
pipe
我读了一些帖子,但似乎对我不起作用。
我restler在客户端服务器和restify其他服务器中使用模块。
restler
restify
谢谢!
抱歉,直言不讳,但这里有很多错误。
readFile在调用回调之前,将文件的 全部内容 读取到内存中,此时您开始上载文件。
readFile
这很不好-特别是在处理图像之类的大文件时-因为实际上没有理由将文件读入内存。这很浪费;在负载下,您会发现服务器的内存不足并崩溃。
相反,您想获得一个 stream ,当从磁盘读取数据时会发出大块数据。您要做的就是将这些块传递到您的上传流(pipe),然后从内存中丢弃数据。这样,您永远不会使用过多的缓冲存储器。
(可读流的默认行为是处理原始二进制数据;仅当您传递时encoding,它才以文本进行处理。)
encoding
该请求模块使得该特别容易:
fs.createReadStream('test.png').pipe(request.post('http://0.0.0.0:5000/'));
在服务器上,您遇到了更大的问题。 切勿使用*Sync方法。 它将阻止您的服务器执行 任何操作 (例如响应其他请求),直到将整个文件刷新到磁盘为止,这可能需要几秒钟的时间。
Sync
因此,我们要获取传入的数据流并将其通过管道传输到文件系统流。您本来是在正确的轨道上;没用的原因req.body.pipe(fs.createWriteStream('test.png'))是因为body它不是流。
body
body由bodyParser中间件生成。在Restify中,该中间件的行为很像readFile,它在内存中缓冲了整个传入的请求实体。在这种情况下,我们不想要那样。禁用主体解析器中间件。
bodyParser
那么传入数据流在哪里?它是req对象本身。restify的Request继承节点的http.IncomingMessage,这是可读流。所以:
req
Request
http.IncomingMessage
fs.createWriteStream('test.png').pipe(req);
我还应该提到,所有这些工作之所以如此简单,是因为不涉及任何形式的解析开销。请求仅发送没有multipart/form-data包装的文件:
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,它可以对请求实体进行流解析。