Rails 中的 Server-sent 个事件未异步传送

Server-sent events in Rails not delivered asynchronously

我正在尝试编写一个 API,它使用 Rails 中的 ActionController::Live::SSE 传递 server-sent 事件 6. 为了理解如何最好地编写测试,我基本上是从 copying the trivial example seen here 开始的: my_controller.rb:

class MyController < ApplicationController
  include ActionController::Live
  def capture
    response.headers['Content-Type'] = 'text/event-stream'
    sse = SSE.new(response.stream)
    3.times do
      sse.write({message: "Awaiting confirmation ..."})
      sleep 2
    end
    fake_response  = { #The response as hash.
     "annotation_id"=>nil,
     "domain"=>"some.random.com",
     "id"=>2216354,
     "path"=>"/flummoxer/",
     "protocol"=>"https",
    }
    sse.write(fake_response, event: 'successful capture')
  rescue => e
    sse.write(e.message, event: 'something broke: ')
  ensure
    response.stream.close
  end
end

当我向此端点发送 curl 请求(无论是 POST 还是 GET)时,响应全部到达一个块,而不是作为单独的响应:

$ curl -i -X GET -H  "Content-Type: application/json" -d '{"url": "https://some.random.com/flummoxer"}' http://localhost:3000/capture
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
ETag: W/"a24048695d2feca40232467f0fbb410a"
X-Request-Id: 648a5229-a43d-40d3-82fd-1c4ea6fe19cc
X-Runtime: 24.082528
Transfer-Encoding: chunked

data: {"message":"Awaiting confirmation ..."}

data: {"message":"Awaiting confirmation ..."}

data: {"message":"Awaiting confirmation ..."}

event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}

在我的测试中,尝试解析来自我的服务器的响应失败这一事实更容易看出这一点:

MultiJson::ParseError: 783: unexpected token at 'data: {"message":"Awaiting confirmation ..."}

data: {"message":"Awaiting confirmation ..."}

data: {"message":"Awaiting confirmation ..."}

event: successful capture
data: {"annotation_id":null,"domain":"some.random.com","id":2216354,"path":"/flummoxer/","protocol":"https"}
'

我的服务器是 Puma,所以

我做错了什么?如果您需要,我会提供可能有用的任何其他信息。

更新: 建议将 -NAccept:text/event-stream header 添加到请求中。这样做不会改变我上面描述的行为——在对 response.stream.close 的调用被触发之前不会发送对请求的响应。

更新 2:我还尝试破解 SSE#write 方法以在 Mutex::ConditionVariable 上调用 broadcast() 以强制发送消息。从它立即发送数据的意义上说,这是可行的,但 curl 请求的副作用是认为流已关闭,因此不会发送更多消息,这不是流。

更新 3:我还修改了 development.rb 以包含 config.allow_concurrency = true,如 here 所示。上述行为没有变化。

我 运行 遇到了与基本 'out the book' Rails 5 SSE 应用程序类似的问题。问题原来是导致流缓冲的机架更新。更多信息在这里 https://github.com/rack/rack/issues/1619 并通过包含

修复

config.middleware.delete Rack::ETag

在config/application.rb