如何在Rails 4中流式传输生成的文件以供下载?

时间:2014-01-04 20:56:38

标签: ruby-on-rails curl streaming unicorn

我希望用户能够点击“下载”链接并在生成文件时下载文件。同样,即使在文件生成完成之前,下载也会立即开始。当我从curl请求时,下面的代码似乎会流式传输,但是在通过firefox或chrome请求启动下载之前等待整个代完成:

class Streamer
  def each  
    1200.times do |i|  
      yield i.to_s + "\n"
      sleep 0.1
    end
    yield "END\n"
  end  
end

class StaticPagesController < ApplicationController

  def stream
    headers["Content-Type"] = "text/plain"
    headers["Content-disposition"] = "attachment; filename=\"test.txt\""
    headers['X-Accel-Buffering'] = 'no'
    headers["Cache-Control"] ||= "no-cache"
    #headers["Transfer-Encoding"] = "chunked"
    headers.delete("Content-Length")
    self.response.status = 200
    self.response_body = Streamer.new
  end

end

取消注释传输编码会中断curl的流式传输。我正在跑步:

bundle exec unicorn_rails --config-file unicorn.config.rb

和unicorn.config.rb是:

listen 3000, tcp_nopush: false, :tcp_nodelay => true

2 个答案:

答案 0 :(得分:0)

我知道这是一个古老的问题,但是如果对某人有用,我将放弃我会遵循的方法。

也许您可以使用后台作业,并创建一个模型,该模型将存储该区域文件以及一些功能信息,例如查找该文件的方式及其当前启动项。

class GeneratedFile < ActiveRecord
 # fields :status, :file_name, :streamed_content, :mime_type, :generation_message
 enum status: %i[processing ready error]
 validates :status, presence: true
end

class StaticPagesController
 def stream
   generating_file = GeneratedFile.create! do |file|
     file.processing!
   end
   # Supposing that this class exist and launches a background job
   BackgroundJob.execute_later(file: generating_file)
 end
end

然后,在执行后台作业期间,您可以修改记录的内容及其状态。

答案 1 :(得分:0)

您发布的示例代码可在Rack 2.1.x上使用,但由于this change in Rack::ETag及其标识流响应的原因,将不再在Rack 2.2.x中流式传输。

在将response_body设置为(鸭型)Enumerable时,您现在需要添加此标头(以防止Rack :: ETag预处理整个Enumerable来构建摘要):

headers["Last-Modified"] = Time.current.httpdate