beego 默认不启用 tcp keepalive 和应用层心跳,需手动配置 http.server 的 setkeepalive 及 setkeepaliveperiod,并自定义 /ping 路由或 websocket ping 逻辑来维持长连接。

Beego 默认不自动处理 HTTP 长连接的心跳(即 TCP 层或应用层保活),它只负责 HTTP 请求/响应生命周期,而长连接复用和心跳是 http.Server 和底层网络栈的事——你得自己补上。
Beego 的 HTTP 服务默认不启用 TCP keepalive
Beego 启动的 http.Server 实例默认未调用 SetKeepAlive,也未设置 SetKeepAlivePeriod。这意味着:即使你用了 HTTP/1.1、没发 Connection: close,操作系统仍可能在空闲数分钟后静默回收连接(尤其在 NAT、云负载均衡后)。
解决方式是手动包装 http.Server:
svr := &http.Server{
Addr: ":8080",
Handler: beego.BeeApp.Handlers,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
}
// 关键:启用 OS 级 TCP keepalive
svr.SetKeepAlive(true)
// 可选:设 keepalive 探测间隔(Linux 默认 2h,太长)
if tcpAddr, ok := svr.Addr.(*net.TCPAddr); ok {
listener, _ := net.ListenTCP("tcp", tcpAddr)
listener.SetKeepAlive(true)
listener.SetKeepAlivePeriod(30 * time.Second) // 每30秒发一次探测包
svr.Serve(listener)
}
- 不调
SetKeepAlive→ 连接可能被中间设备(如 AWS NLB、阿里云 SLB)在 4 分钟左右断开 -
SetKeepAlivePeriod在 Go 1.19+ 才支持;旧版本只能靠应用层心跳兜底 - Beego 的
BeeApp.Run()不暴露http.Server实例,必须绕过它手启服务
Beego 中实现应用层心跳需拦截 WebSocket 或自定义路由
HTTP 协议本身没有标准心跳机制,所谓“心跳”其实是客户端定期发一个轻量请求(如 GET /ping),服务端快速返回 200 OK。Beego 不内置该逻辑,得自己加。
推荐做法是注册一个专用路由:
beego.Router("/ping", &controllers.PingController{}, "get:Ping")
并在控制器中做最小化响应:
func (c *PingController) Ping() {
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/plain")
c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
c.Ctx.ResponseWriter.Write([]byte("ok"))
}
- 避免在
Ping()里调c.Data["json"]或模板渲染,减少 GC 和序列化开销 - 不要依赖
Session或Auth中间件——心跳应绕过鉴权,否则登录态失效会导致假掉线 - 客户端建议用
fetch+keepalive: true(仅 Chromium 系),或用XMLHttpRequest手动控制超时
Beego + WebSocket 场景下,心跳必须由业务代码驱动
Beego 的 WebSocket 支持(beego.WebSocket)封装了 gorilla/websocket,但不自动发送 Ping 帧。如果服务端不主动 WriteMessage(websocket.PingMessage, nil),连接大概率在 60–300 秒后被代理或防火墙掐断。
典型漏点:
- 只在
OnOpen启动 goroutine 发 Ping,但没监听OnClose或 panic 清理,导致 goroutine 泄漏 - Ping 间隔设为 10 秒,但
WriteDeadline是 5 秒 → 频繁触发write deadline exceeded - 用
time.AfterFunc而非time.Ticker,导致多次重叠 Ping
正确写法示例(在 OnOpen 中):
ticker := time.NewTicker(25 * time.Second)
go func() {
defer ticker.Stop()
for {
select {
case <p>最易被忽略的是:Beego 的 HTTP 长连接保活,既不是框架责任,也不是「开了 Keep-Alive 就万事大吉」。它需要你在 TCP 层设 <code>SetKeepAlive</code>、在 HTTP 层防响应体残留、在应用层补心跳逻辑——三层缺一不可,且每层的超时值必须严格套牢(服务端 keepalive timeout </p>











