2012-09-11 70 views
5

我想通過Sinatra應用程序代理遠程文件。這需要將來自遠程源頭的HTTP響應流式傳輸回客戶端,但我無法弄清楚如何在Net::HTTP#get_response提供的塊內使用流式API時設置響應頭。帶有標頭的Sinatra流式響應

例如,這將不設置響應頭:

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 

回答

3

我可能是錯的,但思考了一下這個後出現對我來說,當設置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 

它可能不是適合您的使用情況,因爲額外的要求,但它應該是足夠小,不會有太大的問題(延遲),並將其添加的好處,如果該請求在發回任何數據之前失敗,您的應用程序可能會作出反應。

希望它有幫助。