我想通过Sinatra应用程序代理远程文件.这需要将来自远程源头的HTTP响应流式传输回客户端,但我无法弄清楚如何在使用提供的块内部的流API时设置响应的头Net::HTTP#get_response.
例如,这不会设置响应标头:
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
Run Code Online (Sandbox Code Playgroud)
这会导致错误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
Run Code Online (Sandbox Code Playgroud)
我可能是错的,但经过一番思考后,在我看来,当从stream辅助块内部设置响应标头时,这些标头不会应用到响应中,因为该块的执行实际上被推迟了。因此,可能会在开始执行之前对块进行评估并设置响应标头。
一个可能的解决方法是在流回文件内容之前发出 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
Run Code Online (Sandbox Code Playgroud)
由于额外的请求,它可能不适合您的用例,但它应该足够小,不会造成太大的问题(延迟),并且它增加了一个好处,如果该请求在发回之前失败,您的应用程序可能能够做出反应任何数据。
希望能帮助到你。
| 归档时间: |
|
| 查看次数: |
2620 次 |
| 最近记录: |