news 2026/9/23 8:07:38

使用 Go 实现 SSE 流式推送 + 打字机效果(模拟 Coze Chat)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 Go 实现 SSE 流式推送 + 打字机效果(模拟 Coze Chat)

使用 Go 实现 SSE 流式推送 + 打字机效果(模拟 Coze Chat)

在开发实时聊天、AI 助手或者协作应用时,我们经常需要SSE(Server-Sent Events)实现服务端向前端持续推送数据。本文将分享一个Go SSE 打字机式输出实现,并附上上游模拟示例、curl 测试和前端实时渲染示例。


功能特点

  1. 使用SSE推送消息流,前端无需轮询。
  2. 对消息进行逐字符打字机式输出,模拟 AI 打字效果。
  3. 支持上游 SSE 模拟,方便本地测试。
  4. 可轻松扩展为真实 AI 聊天接口的代理服务。

技术栈

  • Go 1.21+
  • CloudWeGo Hertz 作为 HTTP 框架
  • resty 用于上游 SSE 请求
  • SSE 流式推送(使用hertz-contrib/sse

完整示例代码

packagemainimport("bufio""context""encoding/json""fmt""math/rand""strings""time""github.com/cloudwego/hertz/pkg/app""github.com/cloudwego/hertz/pkg/app/server""github.com/cloudwego/hertz/pkg/common/hlog""github.com/hertz-contrib/sse""resty.dev/v3")funcmain(){h:=server.Default(server.WithHostPorts(":8380"))h.POST("/v3/chat",CozeParseThenTypeWriter)h.GET("/upstream",MockUpstreamSSE)hlog.Info("🚀 Coze SSE parse + typewriter proxy running at :8380")h.Spin()}// 核心逻辑:解析 conversation.message.delta → 打字机式输出funcCozeParseThenTypeWriter(ctx context.Context,c*app.RequestContext){// SSE Headerc.SetStatusCode(200)h:=c.Response.Header h.Set("Content-Type","text/event-stream; charset=utf-8")h.Set("Cache-Control","no-cache, no-store, must-revalidate")h.Set("Pragma","no-cache")h.Set("Connection","keep-alive")h.Set("X-Accel-Buffering","no")stream:=sse.NewStream(c)// Resty 上游请求client:=resty.New().SetTimeout(0)resp,err:=client.R().SetContext(ctx).SetDoNotParseResponse(true).SetHeader("Accept","text/event-stream").Get("http://localhost:8380/upstream")iferr!=nil||resp.RawResponse==nil||resp.RawResponse.Body==nil{hlog.Error("upstream connect failed")return}deferresp.RawResponse.Body.Close()// 打字机准备r:=rand.New(rand.NewSource(time.Now().UnixNano()))scanner:=bufio.NewScanner(resp.RawResponse.Body)varcurrentEventstring// SSE 解析循环forscanner.Scan(){select{case<-ctx.Done():hlog.Warn("client disconnected")returndefault:}line:=scanner.Text()ifline==""{currentEvent=""continue}ifstrings.HasPrefix(line,"event:"){currentEvent=strings.TrimSpace(strings.TrimPrefix(line,"event:"))continue}ifstrings.HasPrefix(line,"data:"){payload:=strings.TrimSpace(strings.TrimPrefix(line,"data:"))ifpayload=="[DONE]"{stream.Publish(&sse.Event{Data:[]byte("[DONE]")})return}ifcurrentEvent=="conversation.message.delta"{vardstruct{Contentstring`json:"content"`}iferr:=json.Unmarshal([]byte(payload),&d);err==nil{typeWriter(stream,r,d.Content)}}ifcurrentEvent=="conversation.message.completed"{stream.Publish(&sse.Event{Event:"conversation.message.completed",Data:[]byte(`{"status":"completed"}`),})}}}}// 打字机逐字符输出functypeWriter(stream*sse.Stream,r*rand.Rand,textstring){fori,ch:=rangetext{time.Sleep(getSleepDuration(r,ch))data:=map[string]any{"id":fmt.Sprintf("char_%d_%d",i,time.Now().UnixNano()%100000),"role":"assistant","type":"answer","content":string(ch),"created_at":time.Now().UnixMilli(),}b,_:=json.Marshal(data)_=stream.Publish(&sse.Event{Event:"conversation.message.delta",ID:fmt.Sprintf("char_%d",i),Data:b,})}}// 延迟策略funcgetSleepDuration(r*rand.Rand,chrune)time.Duration{switch{casech=='\n'||ch=='。'||ch=='!'||ch=='?':returntime.Duration(300+r.Intn(200))*time.Millisecondcasech=='、'||ch==' '||ch=='-'||ch==':'||ch==',':returntime.Duration(150+r.Intn(100))*time.Millisecondcasech=='#'||ch=='*'||ch=='>':returntime.Duration(200+r.Intn(150))*time.Milliseconddefault:returntime.Duration(60+r.Intn(60))*time.Millisecond}}// 上游 Mock(模拟 Coze SSE)funcMockUpstreamSSE(ctx context.Context,c*app.RequestContext){c.SetStatusCode(200)c.Header("Content-Type","text/event-stream")c.Header("Cache-Control","no-cache")c.Header("Connection","keep-alive")c.Header("X-Accel-Buffering","no")c.Flush()send:=func(event,datastring){c.Write([]byte("event: "+event+"\n"+"data: "+data+"\n\n",))c.Flush()}deltas:=[]string{"你","好",",","这","是"," Coze"," SSE"}for_,ch:=rangedeltas{send("conversation.message.delta",`{"content":"`+ch+`"}`)time.Sleep(80*time.Millisecond)}send("conversation.message.completed",`{}`)c.Write([]byte("data: [DONE]\n\n"))c.Flush()}

使用方法

  1. 启动服务
go run main.go
  1. 访问接口
  • 上游 SSE 测试(浏览器可直接访问):
    http://localhost:8380/upstream

  • 打字机代理接口(POST):
    http://localhost:8380/v3/chat


使用curl测试 SSE

# 测试上游 SSEcurl-N http://localhost:8380/upstream# 测试打字机代理 SSEcurl-N -X POST http://localhost:8380/v3/chat

参数说明:

  • -N/--no-buffer:禁用输出缓存,实时显示流式数据。
  • -X POST:因为代理接口是 POST。

运行后,你会在终端看到类似打字机逐字符输出:

event: conversation.message.delta data: {"id":"char_0_12345","role":"assistant","type":"answer","content":"你","created_at":1700000000000} event: conversation.message.delta data: {"id":"char_1_67890","role":"assistant","type":"answer","content":"好","created_at":1700000000050} ... event: conversation.message.completed data: {"status":"completed"} data: [DONE]

前端实时渲染打字机效果示例

在前端,可以使用EventSource监听 SSE 并动态显示内容:

<divid="chat"></div><script>constchatDiv=document.getElementById("chat");constevtSource=newEventSource("http://localhost:8380/v3/chat");evtSource.addEventListener("conversation.message.delta",e=>{constdata=JSON.parse(e.data);chatDiv.innerHTML+=data.content;});evtSource.addEventListener("conversation.message.completed",e=>{console.log("消息完成");});evtSource.onopen=()=>console.log("连接已打开");evtSource.onerror=()=>console.log("连接错误或关闭");</script>

效果:消息逐字符显示,模拟 AI 打字机输出。


核心解析

  1. SSE Header 设置
h.Set("Content-Type","text/event-stream; charset=utf-8")h.Set("Cache-Control","no-cache, no-store, must-revalidate")h.Set("Connection","keep-alive")h.Set("X-Accel-Buffering","no")

保证浏览器或代理实时接收流式数据。

  1. 打字机效果

根据字符类型不同设置不同延迟:

casech=='\n'||ch=='。'||ch=='!'||ch=='?':returntime.Duration(300+r.Intn(200))*time.Millisecond
  1. 上游 SSE 模拟

方便本地测试,无需真实 AI 接口即可验证前端打字机效果。


总结

通过本文示例,你可以快速实现:

  • Go SSE 服务端代理
  • AI 聊天消息打字机式输出
  • 上游 SSE 模拟
  • curl 测试和前端实时渲染
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 12:31:32

元宇宙中的智能体交互难题:90%开发者忽略的延迟一致性陷阱

第一章&#xff1a;元宇宙 Agent 的交互逻辑在元宇宙环境中&#xff0c;Agent 作为虚拟空间中的智能实体&#xff0c;其核心能力体现在与环境、用户及其他 Agent 的动态交互中。这些交互并非简单的事件响应&#xff0c;而是基于感知-决策-执行循环的复杂逻辑体系。Agent 需实时…

作者头像 李华
网站建设 2026/9/23 4:12:40

Unity内置着色器完整使用指南:从入门到精通

Unity内置着色器完整使用指南&#xff1a;从入门到精通 【免费下载链接】Unity-Built-in-Shaders Unity-Built-in-Shaders&#xff1a;提供了Unity游戏引擎内置着色器的非官方代码仓库&#xff0c;对使用Unity进行游戏开发的程序员有帮助。 项目地址: https://gitcode.com/gh…

作者头像 李华
网站建设 2026/9/22 12:10:42

MCP与Azure量子协同容错设计,揭开企业级量子应用稳定性的秘密

第一章&#xff1a;MCP Azure 量子的错误处理在构建基于 MCP&#xff08;Microsoft Quantum Control Program&#xff09;与 Azure Quantum 平台的量子算法时&#xff0c;错误处理是确保计算可靠性的核心环节。量子系统极易受到噪声和退相干影响&#xff0c;因此必须采用软硬件…

作者头像 李华
网站建设 2026/9/22 1:50:32

当JS拷贝玩起了“俄罗斯套娃”:深拷贝与浅拷贝的趣味对决

欢迎使用我的小程序&#x1f447;&#x1f447;&#x1f447;&#x1f447; 俱好用助手功能介绍 &#x1f4da; 拷贝不只是复制粘贴 想象一下&#xff0c;你有一本心爱的精装书&#xff0c;朋友想借去阅读。你有两个选择&#xff1a; 直接给朋友 - 但书就不在你手上了&#…

作者头像 李华
网站建设 2026/9/21 22:38:57

北京创业省钱攻略!0 元注册公司不是梦

北京创业省钱攻略&#xff01;0 元注册公司不是梦 谁说在北京开公司要花大几千&#xff1f;亲身实测&#xff0c;核名、执照办理、刻章备案全程 0 费用&#xff01;工作人员一句话直接让我震惊&#xff1a;“现在北京对初创者的支持力度就是这么大”&#xff0c;当场截图发圈分…

作者头像 李华
网站建设 2026/9/23 4:58:40

行业标杆 | 越秀地产入选「2025年度数据湖仓应用创新先锋企业」

近日&#xff0c;镜舟科技发布“2025 年度数据湖仓应用创新先锋企业”奖项&#xff0c;作为中国第一代商品房缔造者和全国综合性房企领军者&#xff0c;越秀地产凭借其在数据湖仓建设与应用方面的卓越实践成功入选&#xff0c;为房地产行业的数字化转型树立了标杆。一、越秀地产…

作者头像 李华