1. 問題
当 Discourse 配置了 CDN 时,会发生一个常见错误:
/message-bus/204234de907442e8b77e153786a58e5b/poll
连接失败 / 超时 / 状态码异常
影响:
-
通知失败:红点(新私信/回复)不再实时显示;更新可能延迟或根本不出现。
-
实时更新中断:新帖子/点赞/投票不会自动刷新;需要手动刷新页面。
-
用户体验下降:“连接丢失”消息出现;交互延迟。
-
服务器负载增加:前端不断重试轮询,给源站增加压力。
原因:Discourse 使用长轮询来维护实时通信。许多 CDN 会强制执行默认缓存、缩短超时时间、进行挑战/防火墙检查或对长连接进行缓冲,从而导致中断或缓存响应,破坏实时行为。
2. 通用方法(稳定性优先)
-
域名分离:通过专用域名将 MessageBus 路由到源站。
- 论坛域名(通过 CDN):https://bbs.example.com
- MessageBus 域名(无 CDN):https://messagebus.example.com
-
反向代理(Nginx)层:
- 为 /message-bus 启用 CORS。
- 禁用代理缓冲、放宽超时时间、明确禁止缓存。
-
CDN 层(如果仍在使用):
- 将 /message-bus/* 配置为无缓存、延长超时时间、无 JS 挑战/验证码/速率限制,以及 cookie/授权直通。
- 或者完全绕过 CDN。
3. 实现步骤
1) 配置 Discourse 环境变量
编辑 app.yml(通常位于 /var/discourse/containers/app.yml),在 env:: 下添加/修改:
env:
DISCOURSE_MESSAGE_BUS_REDIS_ENABLED: true
DISCOURSE_LONG_POLLING_BASE_URL: "https://messagebus.example.com"
应用更改(官方部署):
cd /var/discourse
./launcher rebuild app
说明:
- DISCOURSE_LONG_POLLING_BASE_URL 告诉前端使用 MessageBus 域名。
- REDIS_ENABLED 应保持启用。
2) DNS 和证书
- 将 messagebus.example.com 直接指向源站,绕过 CDN(最佳实践)。
- 为该域名设置有效的 HTTPS 证书。
3) Nginx(MessageBus 域名)反向代理和 CORS
在 messagebus.example.com 的 server 块中添加或更新以下内容:
location ^~ /message-bus {
# (1) 处理 CORS 预检 (OPTIONS)
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Type' 'text/plain; charset=UTF-8' always;
add_header 'Content-Length' 0 always;
return 204;
}
# (2) 反向代理到 Discourse
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
# 或者,如果是独立部署:
# proxy_pass http://127.0.0.1:3000;
# (3) 防止重复的 CORS 标头
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Credentials;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Max-Age;
# (4) 普通请求的 CORS
add_header 'Access-Control-Allow-Origin' 'https://bbs.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,discourse-deferred-track-view-topic-id,discourse-present,discourse-track-view,discourse-deferred-track-view,x-silence-logger,dont-chunk,x-shared-session-key' always;
# (5) 长轮询稳定性设置
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_connect_timeout 60s;
proxy_buffering off;
add_header X-Accel-Buffering no always;
# (6) 明确禁止缓存
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
}
安全提示:如果使用 Access-Control-Allow-Credentials: true,Origin 不能是 *;它必须与论坛的确切域名匹配。
4) CDN 规则(如果论坛仍通过 CDN)
推荐:为以下路径设置无缓存 + 延长超时时间 + 绕过 WAF/速率限制:
正则表达式示例:
^/(session|login|message-bus|admin|u|users)(/|$)
策略:
- 无浏览器/节点缓存(no-store/no-cache)。
- 上游/读取/空闲超时时间 ≥ 60–120 秒。
- 禁用 JS 挑战/验证码/机器人管理。
- 传递 cookie 和 Authorization 标头(不要剥离)。
4. 如何验证成功
1) 浏览器开发者工具 → 网络
在论坛页面上:
- 观察 /message-bus/…/poll。
- 请求应“挂起”约 20–60 秒,然后返回 200(可能为空)。
- 下一个轮询请求会自动触发。
检查响应标头:
- Access-Control-Allow-Origin: https://bbs.example.com
- Cache-Control: no-store
- 无 Age、X-Cache: HIT 或 CF-Cache-Status: HIT(表示未缓存)。
常见问题:
- 固定的 10 秒/30 秒错误 → 边缘/源站超时。
- 504/524:超时。
- 499:中间层断开连接。
- 403/401:WAF/身份验证阻止。
2) 命令行快速探测(可选)
检查连接性和标头(非完整轮询):
curl -I "https://messagebus.example.com/message-bus/health-check" \
-H "Origin: https://bbs.example.com"
注意:实际轮询需要会话上下文;这仅验证 CORS 和连接性。