Buffalo框架不支持长轮询,因其Action被中间件链封装,含超时与自动响应机制;强行阻塞会导致context超时错误、连接被主动关闭,必须绕过框架用原生http.HandlerFunc手动管理连接与响应。

Buffalo 框架本身不原生支持长轮询(long polling)语义,它基于标准 HTTP handler,所有请求默认立即响应;若强行在 handler 中阻塞等待事件,会耗尽 goroutine 资源、拖垮整个服务。必须手动绕过框架的生命周期控制,用底层 http.ResponseWriter 和 http.Request 直接操作连接。
为什么 Buffalo 的 Action 不能直接写长轮询
Buffalo 的 Action 函数被包装在中间件链中,自带超时、日志、context 取消等逻辑。一旦你在 Action 里 sleep 或 channel wait,框架会在 Context 超时(默认 30s)后主动关闭连接,并抛出 context deadline exceeded 错误——你根本等不到消息到来。
- 框架自动调用
w.WriteHeader()和w.Write(),无法延迟响应头发送 -
c.Response().Writer是封装过的buffalo.Response,底层可能已缓冲或提前 flush - goroutine 不受
Buffalo管理,挂起期间无法被优雅 shutdown
用 http.HandlerFunc 替代 Action 注册长轮询端点
绕过 Buffalo 的路由封装,直接将裸函数注册到 http.ServeMux。这是唯一可控的方式:
func longPollHandler(w http.ResponseWriter, r *http.Request) {
// 关键:禁用框架默认的 header/flush 行为
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
<pre class="brush:php;toolbar:false;">// 必须设置超时略小于 client 侧 timeout,避免 connection reset
timeout := 25 * time.Second
ctx, cancel := context.WithTimeout(r.Context(), timeout)
defer cancel()
// 模拟等待新消息(实际应监听 channel、redis pubsub 或 db change)
select {
case msg := <p>}</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2814" title="Buffalo框架 1.0.1"><img
src="https://img.php.cn/upload/manual/001/589/237/6ab32710f33a7477.png" alt="Buffalo框架 1.0.1" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2814" title="Buffalo框架 1.0.1" class="overflowclass">Buffalo框架 1.0.1</a>
<p class="overflowclass">Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2814" title="Buffalo框架 1.0.1" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>// 在 app.go init() 或 App() 构建后注册
app.ServeMux().HandleFunc("/api/longpoll", longPollHandler)
</p>
- 不要用
app.GET("/api/longpoll", ...),那仍是 Buffalo Action - 确保
messageChan是带缓冲的 channel 或使用select防止 goroutine 泄漏 - 客户端需设置
timeout> 25s,且收到响应后立刻发起下一次请求
如何安全地管理挂起的连接和资源
Buffalo 没有连接池或挂起请求管理机制,你得自己做清理。常见泄漏点:
- 用户断网但 TCP 连接未及时关闭 → 用
http.CloseNotifier(Go 1.8+ 已弃用)不可靠,改用r.Context().Done()监听 - 多个并发请求未限流 → 在 handler 开头加计数器或用
semaphore控制最大挂起数 - 消息广播时遍历所有活跃连接 → 建议用
sync.Map存储*http.ResponseWriter,但注意它不能被多次 write
真正要支撑高并发长轮询,Buffalo 不是合适选型——它定位是快速构建 CRUD Web 应用,不是实时通信网关。该换 gorilla/mux + 手写 WebSocket,或直接上 fasthttp。










