Revel框架本身不内置轮询逻辑,轮询完全由前端控制,后端只需提供标准HTTP接口;关键在于避免session冲突、正确处理CORS、返回合适状态码和缓存头,如禁用轮询接口的session写入、绕过auth重定向、手动设置Cache-Control防止缓存,并用setTimeout递归替代setInterval以防请求堆积。

Revel 框架本身不内置轮询逻辑,Web 端无刷新轮询完全由前端控制,后端只需提供标准 HTTP 接口即可。关键不是“Revel 怎么做轮询”,而是“Revel 怎么配合前端轮询不翻车”——比如避免 session 冲突、正确处理 CORS、返回合适的状态码和缓存头。
前端用 setInterval 轮询时,后端接口要禁用会话写入
Revel 默认每个请求都会尝试写 session(哪怕你没调用 session.Put),这会导致并发轮询请求相互阻塞,尤其在文件 session 存储下,多个 setInterval 请求可能卡住同一 session 文件锁。
- 在轮询用的 controller action 里显式关闭 session 写入:
c.Session.Set("skip-write", "true")不起作用;正确做法是重写Filter或直接在 action 开头调用c.Session.Stop() - 更稳妥的方式:为轮询接口单独配一个不启用 session 的路由,例如在
conf/routes中加GET /api/status StatusController.Status !session(Revel 1.x 支持!session标记) - 若用 Redis session,仍建议禁用——因为轮询请求本就不该携带或更新用户状态,保留 session 会徒增 Redis 压力和过期键数量
fetch 轮询必须手动处理 401 和 403
Revel 的 auth filter(如 auth.Required)在未登录时默认重定向到登录页,但轮询是 fetch 发起的,重定向响应会被静默吞掉,前端只拿到 HTML 内容,response.json() 直接抛错,UI 卡死且无提示。
- 轮询接口必须绕过重定向逻辑:在对应 action 里先检查
c.Request.Header.Get("Accept") == "application/json",如果是 JSON 请求,就直接c.RenderError(401)或c.RenderJSON(map[string]string{"error": "unauthorized"}) - 前端
fetch要检查response.status,遇到 401/403 主动跳转登录页或弹出提示,不能只依赖catch网络错误 - 别依赖
credentials: "include"自动带 cookie——移动端 WebView 或某些浏览器隐私模式下它会失效,轮询失败时连 session 过期都感知不到
轮询间隔设成 60 秒?小心移动端被系统节流
Android Chrome 和 iOS Safari 在页面后台运行时,会把 setInterval 最小间隔拉长到 30–60 秒甚至更久,你设的 60 秒实际可能变成 2 分钟才触发一次,用户切回页面瞬间又涌出一堆积压请求。
- 改用
setTimeout递归调用,每次请求完成后再设下一次,确保「上一次响应结束」才是计时起点,避免请求堆积 - 在
visibilitychange事件里主动重置轮询:document.addEventListener('visibilitychange', () => { if (!document.hidden) startPolling(); }) - 后端接口加上
Cache-Control: no-store, must-revalidate,防止浏览器或中间代理缓存轮询响应——Revel 默认不加这些头,得手动c.Response.Out.Header().Set("Cache-Control", "no-store, must-revalidate")
轮询不是技术难点,难的是让几十个并发请求在 Revel 的 session、filter、header 机制里不互相踩脚。真正上线前,务必用 Chrome DevTools 的 Network → Disable cache + Throttling → Offline 模拟弱网,观察轮询请求是否真的按预期频次发出、是否被重定向吞掉、是否因 session 锁卡住响应时间。


















