首页 > golang > golang中gin配合nginx写一个SSE服务程序
2023
11-17

golang中gin配合nginx写一个SSE服务程序

简介

Server-Sent Events (SSE) 技术是浏览器向服务器发送请求并保持长连接的技术,服务器通过长连接将数据推送到浏览器。SSE通常用于实时更新网页内容或获得服务器推送的通知。


体验过 ChatGPT 官方 Web 工具的同学, 应该了解, AI 对话返回的结果, 不是一次性返回的, 而是会在一段时间内, 持续输出, 就像是人在说话时, 有序地说出每一个字一样.

它是如何实现的呢, 通过 Chrome 检查工具, 可以看到, 它返回的内容类型 (Content-Type) 是 text/event-stream, 而不是我们常用的 application/json

image.png




下面是实现一个基于事件驱动的SSE程序的步骤

1、创建一个HTTP服务器。

2、注册一个路由处理程序,用于处理SSE请求。

3、在路由处理程序中,设置响应头Content-Type为"text/event-stream",并且设置响应头Cache-Control为"no-cache"。

4、将事件写入响应中,用分隔符"\n\n"分隔不同事件的数据。


Go示例

路由部分

//app.aigupiao.com api路由
apiGroup := Router.Group("/goapi")
{
   apiGroup.GET("/ai/sse", ai.SSE)
}

主体实现

func SSE(ctx *gin.Context) {
   // 设置响应头,指定事件源的连接超时时间
   ctx.Writer.Header().Set("Content-Type", "text/event-stream")
   ctx.Writer.Header().Set("Cache-Control", "no-cache")
   ctx.Writer.Header().Set("Connection", "keep-alive")
   ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")


   // SSE格式的数据流
   data := "data: Hello, world!\n\n"
   i := 0
   for {
      if i > 2 {
         break
      }
      i++
      time.Sleep(2 * time.Second)
      fmt.Fprintf(ctx.Writer, data)
      ctx.Writer.Flush()
   }

}

这是一个简单的SSE服务器实现,可以在本地启动一个SSE服务器,在浏览器中访问"http://localhost:8080/ai/sse"即可订阅事件。


客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE test</title>
    <script type="text/javascript">
        const es = new EventSource("/sse/ai/sse");
        es.onmessage = function (e) {
            document.getElementById("test")
                .insertAdjacentHTML("beforeend", "<li>" + e.data + "</li>");
            console.log(e);
        }
        // es.addEventListener("test-event", (e) => {
        //     document.getElementById("test")
        //         .insertAdjacentHTML("beforeend", "<li>" + e.data + "</li>");
        // });
        es.onerror = function (e) {
            // readyState说明
            // 0:浏览器与服务端尚未建立连接或连接已被关闭
            // 1:浏览器与服务端已成功连接,浏览器正在处理接收到的事件及数据
            // 2:浏览器与服务端建立连接失败,客户端不再继续建立与服务端之间的连接
            console.log("readyState = " + e.currentTarget.readyState);
        }
    </script>
</head>
<body>

<h1>SSE test</h1>
<div>
    <ul id="test">
    </ul>
</div>

</body>
</html>


问题注意事项

开发、测试还是挺顺利的, 效果也正常, 但发到线上以后, 一直 loading 转圈, 没有输出, 打开 Chrome 检查工具, 发现请求一直处于 pending 状态...  最后所有内容一起输出


反复查资料, 对比别人的实现; 怀疑是 CORS 跨域问题; 弄到同一个域名下也是一样的问题,突然想到是不是 nginx 反向代理配置的问题, 我的域名网址 www.phpmianshi.com, 是通过 nginx 反向代理到golang的服务端口的. 要验证这个猜想也很简单, 直接用线上gin项目的 ip+port 端口访问测试一下, 果然没有问题!!!


下面是 sse 和  websocket 常用的nginx配置,大家参考,配置后一切正常~~ 

#eventSource
location /es/ {
    proxy_pass  http://请求地址/;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding off;
    proxy_buffering off;
    proxy_cache off;
}
 

#webSocket 
location /api/ws/ {
    proxy_pass  http://请求地址/;
    proxy_redirect off;
    proxy_http_version 1.1;
     proxy_set_header Upgrade $http_upgrade;
     proxy_set_header Connection "upgrade";
 }


本文》有 0 条评论

留下一个回复