问题描述
我正在用Rails 6进行API用例的实验。用户会发布大型请求,这些请求将由Rails接收并流到另一个地方。这可能会与JRuby一起运行,但是现在我正在使用MRI Ruby进行测试。 Web服务器是Puma(开箱即用的导轨安装)。
在上载请求流时,是否有任何方法可以读取请求主体,或者Rails是否需要等待整个请求上载才能访问它?
使用此Curl命令:
curl -i -X PUT -T data.bin "http://localhost:3000/welcome/stream"
这个简单的控制器:
def stream
puts "The stream was called"
io = request.body
until io.eof?
io.read(1024*1024)
puts "Read 1MB"
end
head 200,content_type: "text/html"
end
似乎整个请求都在Rails对其进行访问之前在某个地方上演,因为我的任何put出现在控制台上都需要很长时间。
稍作搜索,似乎是Web服务器(Puma,Unicorn等)缓冲了数据,并且仅在接收到所有数据后才调用Rails。
无论如何,有没有开始读取流的内容,或者避免对其进行缓冲?
是Rack还是Puma进行缓冲?如果是这样,它将在哪里缓冲数据?
解决方法
是Rack还是Puma进行缓冲?如果是这样,它将在哪里缓冲数据?
服务器会收集整个流,然后再将其传递给Rack / Rails ...,这样您就无法在主体完全上传之前开始处理请求。
进行此设计的理由很充分,因为服务器将使用可用线程来轮询IO而不是进行阻塞,从而使您的应用程序可以在后台执行IO操作的同时处理其他请求。
否则,当您的应用程序在不完整的流上调用read
时,IO将阻塞线程(并扩展为服务器),从而导致并发性失败。
无论如何,有没有开始读取流的内容,或者避免对其进行缓冲?
您可以实现自己的服务器(不建议使用),也可以使用AJAX / WebSockets(更常见的方法)上传点点滴滴。