ruby - 带有 header 的 Sinatra 流式响应

标签 ruby sinatra

我想通过 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/

相关文章:

ruby - 在 Ruby Hash 的开头插入元素?

ruby-on-rails - 如何在 Sinatra 中组织模型?

error-handling - Sinatra和Ubuntu上生产中的自定义漂亮错误

arrays - 从子字符串作为另一个项目存在的数组中删除项目(超字符串)

Ruby Sinatra 验证向 View 返回错误

ruby - Sinatra assetpack 没有将 sass 编译成 css

json - 如何清理进入 Sinatra 应用程序的所有参数?

ruby-on-rails - 如何使用 ruby​​ 在新窗口中打开链接?

MySQL语句通过关系表根据多个条件获取记录

MySQL:不正确的日期值