class StreamController < ActionController::API
include ActionController::Live
before_action do
response.headers['Content-Type'] = 'text/event-stream'
response.headers["Last-Modified"] = Time.now.httpdate # TODO 3
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
response.headers['Cache-Control'] = 'no-cache'
response.headers['Connection'] = 'keep-alive'
@sse = SSE.new(response.stream) # TODO 1
end
rescue_from(ActiveRecord::RecordNotFound) do |e|
@sse.write(status: 404, message: e.message.to_s)
@sse.close
end
# params
# {
# chat_id: 1,
# content: 'Hello',
# }
def talk
Chats::GetAnswer.execute(params, @sse)
# ensure # TODO 2
# @sse.close
end
end
开发时候主要碰到几个问题
TODO 1. SSE.new(response.stream, retry: 300), 返回 sse 数据时,会把 retry: 300 返回,这个是正常?
TODO 2. ensure 这里不可以 close, 因为 rescue_from 的执行是在 ensure 之后的,有没有更优雅的写法
TODO 3. 感谢 rennyallen 的 https://ruby-china.org/topics/43052 这篇文章,rack >= 2.2x 需要加上这行
TODO 4. 如果你用 nginx proxy, 还需要再 conf 文件里加上 proxy_set_header Connection ''; proxy_http_version 1.1; chunked_transfer_encoding off;
总结:sse 在 rails 里还是做不到开箱即用,有些细节和小坑要注意下