ActionController ::与SSE一起生活不正常

时间:2013-11-08 11:51:21

标签: ruby-on-rails ruby-on-rails-4 live-streaming actioncontroller

我正在尝试在一个项目中使用Rails 4.0.1中的直播,但我发现问题......

我有这个动作:

def realtime_push
    response.headers['Content-Type'] = 'text/event-stream'

    sse = SSE.new(response.stream)

    d = Domain.find(params[:domain_id])

    begin
      loop do
        backlinks = d.backlinks.page(params[:page]).per(10)
        pagination = render_to_string(:partial => 'backlinks/pagination', :layout => false, :locals => { :backlinks => backlinks })
        sse.write({ :html => pagination }, :event => 'pagination')
        sleep 1
      end
    rescue IOError
      # When the client disconnects, we'll get an IOError on write
      logger.debug "DISCONNECTED"
    ensure
      sse.close
    end
end

当我开始使用Puma并尝试获取更新时:

curl http://localhost:3000/domains/16/backlinks/realtime_push

卷曲立即返回,没有输出。

卷曲标题:

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Content-Type: text/event-stream
Cache-Control: no-cache
X-Request-Id: 1a07be2f-de8d-4ca8-87d0-eee2787ea649
X-Runtime: 0.250782
Transfer-Encoding: chunked

和Puma日志显示:

Started GET "/domains/16/backlinks/realtime_push" for 127.0.0.1 at 2013-11-08 12:22:30 +0100
  ActiveRecord::SchemaMigration Load (0.7ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by BacklinksController#realtime_push as */*
  Parameters: {"domain_id"=>"16"}
  Domain Load (1.9ms)  SELECT "domains".* FROM "domains" WHERE "domains"."id" = $1 LIMIT 1  [["id", "16"]]
   (3.3ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (60.6ms)
   (0.6ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (36.0ms)
   (0.8ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (37.5ms)
   (0.8ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (35.6ms)
   (0.7ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (38.7ms)
   (0.7ms)  SELECT COUNT(*) FROM "backlinks" WHERE "backlinks"."domain_id" = $1  [["domain_id", 16]]
  Rendered backlinks/_pagination.haml (37.0ms)

所以这些事情很奇怪:

  • curl没有输出
  • 日志表示它会分页6次
  • 日志中没有“DISCONNECT”消息

有什么想法吗?如果我将sse.write上面的两行注释掉并返回一些文本而不是分页内容,那么它就可以...

这是SSE课程:

class SSE
  def initialize io
    @io = io
  end

  def write object, options = {}
    options.each do |k,v|
      @io.write "#{k}: #{v}\n"
    end
    @io.write "data: #{JSON.dump(object)}\n\n"
  end

  def close
    @io.close
  end
end

1 个答案:

答案 0 :(得分:1)

这是render_to_string中的错误。

修补此问题的补丁(实际上无法解决问题 - 请参阅下文):

def render_to_string(*)
  orig_stream = response.stream
  super
ensure
  if orig_stream
    response.instance_variable_set(:@stream, orig_stream)
  end
end

来源:http://blog.sorah.jp/2013/07/28/render_to_string-in-ac-live

更新:这只出现来修复问题...虽然它会导致控制器实际发送数据,但由于某些原因,JavaScript中的接收端仍然不会收到事件通知,见这里:SSE (Server-sent events) not working