ActionController::Live with SSE not working properly

匿名 (未验证) 提交于 2019-12-03 10:24:21

问题:

I'm trying to use Live Streaming in Rails 4.0.1 in one project but I see problems...

I have this action:

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

When I start Puma and try to get updates:

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

curl immediately returns with no output.

Curl headers:

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

and Puma log shows:

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)

So these things are strange:

  • curl returned no output
  • log says it rendered pagination 6 times
  • there was no "DISCONNECT" message in the log

Any ideas? If I comment out the two lines above sse.write and return some text instead of pagination contents, it works...

Here is the SSE class:

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:

This is a bug in render_to_string.

Monkey patch to fix this (that actually doesn't fix the problem - see below):

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

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

UPDATE: this only appears to fix the problem... although it will cause the controller to actually send the data, the receiving end in JavaScript for some reason still won't get notified of events, see here: SSE (Server-sent events) not working



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!