最近得知平时与我对接的后端要离职,而公司暂时还没有招人的打算。所以部门负责人找到我说,让我先接替后端的工作。我当时表面上对后端的离职还是表示遗憾,但内心还是很乐意的。一来我很早也想过学习一门后端语言;二来公司现在也不是很忙,所以压力也不是很大。
对于前端来说后端相关知识应该不是很陌生,也有很多前端人转做大前端或者全栈。另外这两年由于AI的兴起,很多公司都在降本增效,更加速了这样一个趋势。记得前几年我还做过Node.js 中间层相关的工作,对于数据库的简单增删查改和服务器部署还是熟悉的。虽然这次接手的是go语言的后端项目,但我觉得但凡做过几年开发,快速熟悉一门新语言不是什么难事,更何况现在AI这么强,简直是一大神助力,哈哈。
go作为后端服务的优劣势
优势:
1、语法简单,学习成本低
Go 仅 25 个关键字,剔除继承、重载、泛型早期缺失(1.18 补齐)、复杂面向对象;代码风格统一(gofmt 强制格式化),团队代码风格不会乱。
2、部署简单
直接静态编译,输出单个二进制文件,无 JVM、无依赖包;服务器只传一个文件就能运行,跨平台交叉编译轻松。
3、轻量级,支持高并发
goroutine 由运行时调度,栈初始仅 2KB,百万并发协程内存占用可控;搭配 channel 做通信,并发代码简洁、无线程池繁琐配置。
4、原生配套云原生生态
Docker、K8s、etcd、prometheus、istio 等云原生基础设施几乎都是 Go 开发;标准库自带 http、rpc、加密、并发工具,无需大量第三方框架。
劣势:
相对于java这种传统后端服务来说,go的能力还不够丰富,不适合大型复杂的企业级系统。
接手后端项目
我接手go后端项目做的第一件事是了解后端服务如何启动和部署,以及aws上各种云服务的对接配置等。

第二件就是重构了后端的代码结构,之前项目全部都是go文件,一个文件上千行。现在做了标准go后端服务的代码结构,但目前还没分controller、service、repository等。

第三件就是修改了几个后端bug练练手,当然都是让Ai来修改,都是一次搞定,完美!
需求开发(AI Coding)
再后面产品提了一个消息管理的需求:首先需要在管理后台配置对应操作的触发节点,待前台社区用户的登录/注册/点赞/收藏等操作后,然后推送给对应用户。
这个需求不算难,主要是在相关操作接口根据配置的触发模板,动态生成消息内容,然后推送给对应用户。
但是我前端代码都不会写了,更何况后端。
所以我还是熟练的将需求描述和原型图喂给codex,让它先整理一版开发计划以及需要注点。
几分钟之后,codex 就给出了详细的开发计划,以及需要建的数据库表。由于目前数据库表需要我手动到数据库执行,所以我会让它直接生成sql 执行脚本,方便我执行。至于后需要的开发步骤,我就全盘交给Ai来处理。Ai开发完后端代码后,对应接口我会先到Postman测试一下,一般来说都没什么问题,后续直接让Ai生成前端可对接的文档即可。
SSE(Server-Sent Events)服务端实时推送
这个需求还涉及到消息实时推送功能,就是前端消息数量需要实时同步。一开始我能想到的就是WebSocket 和前端轮询,但想到WebSocket 比较麻烦,而前端轮询以前写过很多,而且轮询频率高的话前端控制台一大推请求看着不爽。于是先让Ai给了一下推荐方案,Ai推荐SSE (Server-Sent Events 服务器发送事件)。这是一套单向长连接实时通信的 Web 标准(HTML5 规范),简单说就是:浏览器发起一次 HTTP 请求,服务器持续往客户端推送数据,全程只有服务端发消息,客户端不能发数据。秒啊,完美符合我的需求,不仅比WS轻量而且只发送一次http请求。
一、是什么
**SSE 全称 Server-Sent Events,服务器发送事件**,是一套**单向实时通信**的 Web 标准(HTML5 规范)。
简单说:**浏览器发起一次 HTTP 请求,服务器持续往客户端推送数据,全程只有服务端发消息,客户端不能发数据**。
和 WebSocket 最大区别:
-
SSE:**单向**(服务端 → 客户端),基于普通 HTTP/HTTPS
-
WebSocket:**双向**(客户端↔服务端),握手后切换长连接协议
二、核心原理
-
客户端用浏览器内置 `EventSource` API 发起 GET 请求;
-
服务端响应头特殊标识,告诉浏览器这是 SSE 长连接:
```http
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
```
-
连接不关闭,服务端不断按固定格式分段写入数据;
-
浏览器自动解析数据流,触发 `onmessage` 事件拿到消息;
-
网络断开后,`EventSource` **自动重连**(自带断线恢复)。
三、服务端消息固定格式
每条消息由多行字段组成,**空行代表一条消息结束**
```
data: 消息内容
event: 自定义事件名(可选)
id: 消息ID(用于断线重连补发)
retry: 重连毫秒间隔(可选)
```
示例:
```
data: {"count":"3"}
```
四、优缺点对比
优点
-
**基于原生 HTTP**,不用额外协议,Nginx/Apache 天然支持,无需升级协议;
-
浏览器原生 `EventSource`,不用第三方 JS 库;
-
内置**自动断线重连**、消息ID断点续传;
-
轻量,适合纯展示类实时场景,开销比 WebSocket 小;
-
支持跨域标准 CORS。
缺点
-
**单向通信**,客户端无法发数据给服务端;
-
只能用 GET 请求,不支持 POST;
-
部分老浏览器兼容差(现代浏览器都支持);
-
受浏览器**最大并发连接数限制**(同域名最多6个SSE长连接)。
五、适用场景
只需要**服务端主动推、前端只接收**的场景:
-
实时数据大屏(监控指标、订单统计、库存刷新)
-
消息通知、系统公告、站内提醒
-
日志实时打印、AI 流式输出(ChatGPT/文心一言打字机效果)
-
股票、行情、传感器实时数值刷新
-
进度推送(文件导出、任务执行进度)
六、典型代码示例
1.前端 JS(EventSource)
perl
// 建立SSE连接const sse = new EventSource("/api/sse/stream");// 接收普通消息sse.onmessage = (e) => {console.log("收到推送:", JSON.parse(e.data));};// 监听自定义event事件sse.addEventListener("notice", (e) => {alert("系统通知:" + e.data);});// 连接出错、断开自动重连sse.onerror = () => {console.log("连接异常,自动重试");};// 手动关闭连接// sse.close();
2.Go 后端极简示例
vbnet
func SSEStream(w http.ResponseWriter, r *http.Request) {// 设置SSE必须响应头w.Header().Set("Content-Type", "text/event-stream")w.Header().Set("Cache-Control", "no-cache")w.Header().Set("Connection", "keep-alive")flusher, ok := w.(http.Flusher)if !ok {http.Error(w, "不支持流输出", 500)return}// 持续循环推送tick := time.Tick(2 * time.Second)for range tick {msg := `data: {"time":"` + time.Now().Format(time.RFC3339) + `"}\n\n`_, _ = w.Write([]byte(msg))flusher.Flush() // 强制刷入TCP流,不缓存}}
七、和 WebSocket 选型怎么选?
- **只用服务端下发、前端不上传数据** → SSE(简单、稳定、易部署)
如:大屏、AI流式输出、实时统计、通知
- **前后端需要互相收发消息** → WebSocket
如:聊天、在线协同、实时对战、双向交互
八、后端开发注意点
-
必须开启 Response 流刷新(Flush),否则消息会被缓冲区堆积;
-
长连接会占用服务端协程/线程,高并发场景要做连接管理、超时清理;
-
断线重连配合 `Last-Event-ID` 请求头,实现消息补发;
-
Nginx 反向代理时要关闭缓冲:`proxy_buffering off;`,否则推送延迟。
补充:AI流式输出为什么大量用SSE
大模型打字效果(逐字输出)不需要前端发消息,服务端分段返回文本,SSE 轻量简单,不用维护 WS 连接状态,现在几乎所有对话类AI接口都是基于 SSE 实现流式返回。