thinkphp消息推送无统一标准,短时低频用ajax轮询(如3分钟间隔+缓存未读数),中高频或双向交互推荐think-worker websocket,单向广播可用sse,第三方推送需封装http api并注意环境隔离与设备id更新。

ThinkPHP 实现消息推送接口,没有统一“标准答案”,关键看你要推什么、推给谁、实时性要求多高。直接上结论:短时低频用 ajax 轮询;中高频或需双向交互用 WebSocket(推荐 think-worker);单向广播类场景可选 SSE;第三方通道(如极光、腾讯信鸽)则走 HTTP API 封装。
ajax 轮询接口怎么写才不卡顿、不漏数据
轮询本质是客户端定时发请求查新消息,适合通知类(如未读数、系统公告),不适合聊天或强实时场景。
- 避免高频请求:前端用
window.setInterval间隔至少 30s,别设成 1s 或 5s,否则服务器压力陡增 - 后端必须加缓存:不要每次查数据库,用
cache('notify_count_'.$uid, $count, 60)缓存 60 秒,命中率高且减轻 DB 压力 - 注意并发竞争:多个标签页同时轮询,可能重复标记已读;建议在更新
isscan=1时加 where 条件:->where('isscan', 0)->update(['isscan' => 1]),靠影响行数判断是否真正处理过 - 返回格式要稳定:始终返回 JSON,字段名统一(如
{"code":0,"data":{"count":5}}),前端用res.data.count取值,别依赖res.result这类易变字段
用 think-worker 启动 WebSocket 服务常见启动失败原因
think-worker 是 ThinkPHP 官方维护的 Workerman 封装,但配置错一个参数就起不来,尤其在 Linux 生产环境。
-
gateway_worker.php中'businessWorker' => ['eventHandler' => 'xxx']的类路径必须带完整命名空间,比如\app\common\event\WorkerHandler,少个反斜杠或大小写不对都会报Class not found - Redis 驱动队列启用后,
worker:gateway命令默认不加载队列配置,得手动在WorkerHandler里调用Queue::push()或监听事件,否则消息进不了队列 - Windows 下无法启动:Workerman 不支持 Windows 的信号机制,必须用 WSL 或 Docker;若强行运行,会卡在
pcntl_signal报错,别硬试 - 端口被占或防火墙拦截:启动后检查
netstat -tuln | grep 2358(默认端口),并确认云服务器安全组放行该端口,否则前端连不上ws://your-domain.com:2358
SSE 接口在 ThinkPHP 中如何避免连接自动断开
SSE(Server-Sent Events)适合服务端单向广播(如日志流、AI 回答流),但 PHP 默认超时和输出缓冲常导致连接中断。
- 必须禁用输出缓冲:
ob_end_clean()+ini_set('output_buffering', 'off')+ini_set('zlib.output_compression', false) - 响应头不能少:
header('Content-Type: text/event-stream')、header('Cache-Control: no-cache')、header('X-Accel-Buffering: no')(Nginx 专用) - 每次发送数据后要
flush()和ob_flush(),且数据块格式必须为data: xxx\n\n(结尾两个换行),少一个\n浏览器就不解析 - ThinkPHP 的中间件可能拦截长连接:把 SSE 方法路由单独配到不经过权限/日志中间件的分组里,否则中间件超时会 kill 掉连接
调用极光/个推等第三方推送 SDK 的坑点
第三方推送不是“填个 AppKey 就能发”,实际集成中权限、签名、设备绑定三处最容易翻车。
- AppKey 和 MasterSecret 必须严格区分环境:测试用的 key 绝对不能写死在生产 config 里,要用
Env::get('jpush.app_key')从 .env 加载 - 极光 SDK 的
JPushClient初始化后,调用push()前必须先setProductionMode(true),否则 iOS 线上证书不生效,安卓收得到但 iOS 没反应 - 设备 registration_id 不是永久有效:用户卸载重装、清除应用数据后 ID 会变,后台必须监听客户端上报的新 ID 并覆盖旧记录,否则推送就石沉大海
- 别在控制器里直接 new JPushClient:应封装成 service 类,用容器注入,方便 mock 测试和替换其他推送服务商
真正难的不是写通一个推送接口,而是让「推送到达率」和「用户感知延迟」可控——这取决于你选的协议是否匹配业务节奏、服务部署是否规避了超时链路、以及设备端是否完成了可靠绑定。每种方案都只解决一部分问题,混用才是常态。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











