openresty代理SSE请求lua-resty-sse

什么是SSE

服务器向浏览器推送信息,除了 WebSocket,还有一种方法:Server-Sent Events(以下简称 SSE)。

严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。

也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。

SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 HTTP 协议,目前除了 IE/Edge,其他浏览器都支持。

SSE特点

SSE 与 WebSocket 作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息。

总体来说,WebSocket 更强大和灵活。因为它是全双工通道,可以双向通信;SSE 是单向通道,只能服务器向浏览器发送,因为流信息本质上就是下载。如果浏览器向服务器发送信息,就变成了另一次 HTTP 请求。

  • SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。

  • SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。

  • SSE 默认支持断线重连,WebSocket 需要自己实现。

  • SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。

  • SSE 支持自定义发送的消息类型。

数据格式

服务器向浏览器发送的 SSE 数据,必须是 UTF-8 编码的文本,具有如下的 HTTP 头信息:

Content-Type: text/event-stream

Cache-Control: no-cache

Connection: keep-alive

每一次发送的信息,由若干个message组成,每个message之间用\n\n分隔。每个message内部由若干行组成,每一行都是如下格式。

[field]: value\n

field可以取四个值:

data
event
id
retry

此外,还可以有冒号开头的行,表示注释。通常,服务器每隔一段时间就会向浏览器发送一个注释,保持连接不中断。

: This is a comment

总之,服务端发送的是字符串文本,一条数据有多个\n分行,\n\n表示一条完整数据的结束。
SSE更详细信息参考,介绍的简单易懂很详细

openresty开发代理SSE请求

引入sse.lua库 ,需要依赖 ledgetech/lua-resty-http(opm get ledgetech/lua-resty-http安装引用即可)。

如何使用:

location /sse_proxy {
    lua_check_client_abort on;
    content_by_lua_block {
              local sse = require("sse")

              local function return_client_res(res)
                  ngx.status = res.status
                  for k, v in pairs(res.header)  do
                      ngx.header[k] = v
                  end
                  ngx.say(res.body)
                  return ngx.exit(ngx.status)
              end

              local function my_cleanup()
                  -- need config lua_check_client_abort on;
                  ngx.log(ngx.NOTICE,"onabort exit 499")
                  ngx.exit(499)
              end
          
              local ok, err0 = ngx.on_abort(my_cleanup)
              if not ok then
                  ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err0)
              end
          
              local conn, err = sse.new()
              if not conn then
                  ngx.log(ngx.ERR,"failed to get connection: ", err)
                  return
              end
              --conn:set_timeout(50000)
              local path = 'http://127.0.0.1:8080/events/123'
          
              local res, err2, is_sse_resp = conn:request_uri(path,{
                  headers = req_headers,
                  ssl_verify = false
              })
              if not res then
                  ngx.log(ngx.ERR,"failed to request: ", err2)
                  return
              end

            -- response header同步
              conn:transfer_encoding_is_chunked()   --有Transfer-Encoding:chunked,需要去掉
              for k, v in pairs(res.headers)  do
                     ngx.header[k] = v
              end

              while is_sse_resp
              do
                  local event, err3 = conn:receive()
                  if err3 then
                      ngx.log(ngx.ERR,"sse request over"..err3)
                      return ngx.exit(ngx.HTTP_OK)
                  end
                  if event then
                      ngx.log(ngx.NOTICE,"sse received success, event="..event)
                      ngx.print(event)
                      ngx.flush()   -- 一定要flush
                  end
              end
              -- not content-type:text/event-steam
              ngx.status=res.status
              ngx.say(res.body)
              return ngx.exit(ngx.status)
    }
}

更多内容

https://github.com/ldongxu/openresty-starter 这里有更详细的openresty脚手架项目,包括http、websocket、sse,也有springboot开发的SSE服务demo供调试使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值