我想通过 Sinatra 应用程序代理远程文件。这需要将带有 header 的 HTTP 响应从远程源流式传输回客户端,但我不知道如何在 Net::HTTP# 提供的 block 内使用流式 API 时设置响应 header 获取响应
。
例如,这不会设置响应头:
get '/file' do
stream do |out|
uri = URI("http://manuals.info.apple.com/en/ipad_user_guide.pdf")
Net::HTTP.get_response(uri) do |file|
headers 'Content-Type' => file.header['Content-Type']
file.read_body { |chunk| out << chunk }
end
end
end
这会导致错误:Net::HTTPOK#read_body called twice (IOError)
:
get '/file' do
response = nil
uri = URI("http://manuals.info.apple.com/en/ipad_user_guide.pdf")
Net::HTTP.get_response(uri) do |file|
headers 'Content-Type' => file.header['Content-Type']
response = stream do |out|
file.read_body { |chunk| out << chunk }
end
end
response
end
最佳答案
我可能是错的,但在仔细考虑之后,在我看来,当从 stream
帮助程序 block 内部设置响应 header 时,这些 header 不会应用到响应中,因为该 block 的执行实际上被延迟。因此,可能会在 block 开始执行之前评估该 block 并设置响应 header 。。
一个可能的解决方法是在流回文件内容之前发出 HEAD 请求。
例如:
get '/file' do
uri = URI('http://manuals.info.apple.com/en/ipad_user_guide.pdf')
# get only header data
head = Net::HTTP.start(uri.host, uri.port) do |http|
http.head(uri.request_uri)
end
# set headers accordingly (all that apply)
headers 'Content-Type' => head['Content-Type']
# stream back the contents
stream do |out|
Net::HTTP.get_response(uri) do |f|
f.read_body { |ch| out << ch }
end
end
end
由于额外的请求,它可能不适合您的用例,但它应该足够小,不会造成太大问题(延迟),并且它增加了一个好处,即如果该请求失败,您的应用可能能够使用react在发回任何数据之前。
希望对您有所帮助。
关于ruby - 带有 header 的 Sinatra 流式响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12361161/