frankenphp后台任务进度推送必须用mercure而非websocket,因它原生不支持websocket;worker.php中需用frankenphp\publish()函数发布json格式进度事件,前端用eventsource订阅/mercure?topic=xxx,且任务必须运行在frankenphp worker模式下。

FrankenPHP 后台任务进度推送必须用 Mercure,不是 WebSocket
FrankenPHP 原生不支持 WebSocket,也没有内置的长连接通道;它通过 Mercure 协议实现服务端向客户端的实时推送,这是唯一被官方深度集成、无需额外中间件的方案。试图复用 Ratchet 或 Swoole 的 WebSocket 实现,会破坏 FrankenPHP 的进程模型——worker 进程无法持有持久 socket 连接,且与 Caddy 的 HTTP/2 流量层冲突。
Mercure 的核心是“发布-订阅”:后台任务(如 worker)向 Mercure Hub 发送更新,前端通过 EventSource 订阅对应主题,整个链路由 FrankenPHP 内置的 Mercure 服务代理,无需你单独部署 Hub(除非自定义配置)。
worker.php 中怎么发进度事件到 Mercure
在 worker.php 里不能直接调用 curl 或手动构造 HTTP 请求发给 Mercure —— 这样做不可靠、无重试、不带认证头,且容易因网络抖动丢失事件。正确方式是使用 FrankenPHP 提供的 frankenphp\publish() 函数:
-
frankenphp\publish()自动处理 JWT 签名、目标 Hub 地址、Content-Type 和重试逻辑 - 必须传入
$topic(字符串,如"progress/task-123"),前端按此订阅 - 数据需为合法 JSON(
array或string),不能是 PHP 对象或资源 - 推荐结构:
["progress" => 65, "status" => "processing", "message" => "已压缩 12/18 张图片"]
示例:
use frankenphp;
// 在 worker 循环中
for ($i = 0; $i $i,
'status' => $i === 100 ? 'completed' : 'processing',
'step' => $i / 20,
]);
}
前端用 EventSource 订阅进度,别用 fetch 或 axios
fetch 和 axios 是短连接,无法维持服务端推送通道;必须用浏览器原生 EventSource。它自动重连、解析 text/event-stream 格式,并触发 message 事件。
关键点:
- URL 必须以
/mercure开头(FrankenPHP 默认路由),且带topic查询参数:/mercure?topic=progress%2Ftask-123 - 不要手动加
Authorization头 —— Mercure 认证由服务端 JWT cookie 或 URL token 完成,前端只需发起 GET - 监听
error事件并做降级处理(比如轮询 fallback)
简短示例:
const es = new EventSource('/mercure?topic=progress%2Ftask-123');
es.onmessage = (e) => {
const data = JSON.parse(e.data);
console.log('进度:', data.progress);
document.getElementById('progress-bar').style.width = data.progress + '%';
};
es.onerror = () => {
console.warn('Mercure 连接中断,启用轮询');
};
为什么不能在 PHP-FPM 或传统 Laravel Artisan 命令里用 Mercure 推送
因为 Mercure 推送依赖 FrankenPHP 运行时上下文:frankenphp\publish() 函数内部调用的是 Go 层的 hub.Publish(),而该 hub 实例只在 FrankenPHP 主进程初始化时创建。在普通 CLI 模式(如 php artisan queue:work)下运行,frankenphp 扩展根本未加载,调用 publish() 会直接报 Fatal error: Uncaught Error: Call to undefined function frankenphp\publish()。
所以必须满足两个条件:
- 任务代码运行在 FrankenPHP 的
worker模式下(即由frankenphp-worker启动的进程) - 项目使用 FrankenPHP 作为 Web Server(而非 Nginx + PHP-FPM),否则 Mercure 路由和 Hub 不可用
如果你当前是 Laravel 项目,得把后台任务从 queue:work 迁移到 async:franken 命令,并确保用 trueasync/php-true-async:latest-frankenphp 镜像启动。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











