1

我正在尝试在一个项目中使用 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

curl 立即返回,没有输出。

卷曲标题:

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

和彪马日志显示:

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
4

1 回答 1

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(服务器发送事件) 不工作

于 2013-11-09T19:46:46.827 回答