Appearance
后端推送服务
本页只描述 Web 访客端、Web 客服端和 PHP 后端之间的推送。浏览器不应持有 appsecret,也不应直接调用 Socket 服务的内部 HTTP API。
配置关系
Socket 进程由 config/process.php 注册。它对外维护 WebSocket 连接,对内提供 HTTP 推送入口;app\service\Push 从数据库设置中读取 api_address、appkey、appsecret,并通过 PushApi 完成签名请求。
text
业务 Controller / Service
│
│ Push::emit(channel, event, data)
v
app\service\Push
│ 内部 HTTP + 签名
v
Socket 进程
│ WebSocket
v
浏览器订阅频道Push 构造时从 setting 表读取以下配置。它们只属于后端运行环境:
| 设置 | 用途 | 安全要求 |
|---|---|---|
api_address | Socket 内部 HTTP 推送地址。 | 仅允许应用服务器访问。 |
appkey | Socket 应用标识。 | 可随客户端初始化配置下发。 |
appsecret | 内部推送签名密钥。 | 只能保存在后端,绝不下发浏览器。 |
PushApi 的内部请求默认超时为 2 秒。业务代码不应在长事务中无限等待推送返回。
后端发送事件
业务代码只使用 Push:
php
use app\service\Push;
$push = new Push();
$result = $push->emit(
agent_channel($agentId),
'message.created',
[
'uid' => $uid,
'agent_id' => $agentId,
'content' => $content,
'author' => 'agent',
'sub_type' => 'message',
'mid' => $mid,
'timestamp' => time(),
]
);
if ($result['status'] !== 200) {
// 记录失败并按业务需要处理
}| 参数 | 用途 |
|---|---|
$channel | 接收频道。客服使用 agent_channel($agentId);访客使用 visitor_channel($bid, $uid)。 |
$event | 事件名,例如 message.created、message.read、conversation.ended。 |
$data | 事件负载。不同事件使用不同字段,具体见“会话与消息事件”。 |
$result.status | 200 表示 Socket 服务接受推送;其他值表示推送失败。 |
频道约定
不要在业务 Controller 中手写频道格式。项目已有辅助方法用于访客与客服频道:
php
$visitorChannel = visitor_channel($bid, $uid);
$agentChannel = agent_channel($agentId);
$globalChannel = 'global-' . $bid;| 频道 | 接收者 | 适合发送的事件 |
|---|---|---|
visitor-... | 当前访客的浏览器会话 | 新消息、已读、撤回、会话结束、评分与解决状态。 |
agent-{agentId} | 指定客服的工作台 | 新消息、输入中、转接、结束、隐藏和会话更新。 |
global-{bid} | 当前商户已连接的页面 | 设置、客服在线状态、访客资料、上下文和标签定义变化。 |
消息写入后通常应同时推送访客频道与接待客服频道;只向一端推送会造成另一端页面不能实时更新。
事件设计要求
- 使用已存在的点分事件名,例如
message.created、message.read、conversation.transferred;不要新增同义的横线或下划线事件名。 - 消息事件必须包含能定位服务端消息的
mid,并带上uid、agent_id、author、sub_type、content等实际需要的字段。 Push对message.created与message.translated会根据已落库消息补充标准化字段;应先写入数据库,再调用emit()。- 全局频道使用补丁数据。只传发生改变的字段,接收端按字段合并。
- 事件负载不能包含密码、Session、Token、
appsecret或内部服务地址。
失败与一致性
status: 200 仅表示 Socket 服务已接受内部请求,不表示每个浏览器都已收到事件。因此数据一致性策略应为:
text
先提交业务数据
↓
调用 Push::emit 发送增量通知
↓
浏览器按 mid / 业务 ID 幂等合并
↓
断线、失败或未知状态时由 HTTP 查询补齐对关键业务操作,推送失败应记录服务端日志并保留已提交的业务结果;不要因为仅推送失败而回滚已经成功保存的消息或会话。客户端重连后的历史补拉是最终恢复机制。
开发调试
- 确认数据库
setting中的api_address、appkey、appsecret与 Socket 进程配置一致。 - 在业务写入成功后检查
$result['status']和$result['body']。 - 浏览器确认订阅的频道与服务端目标频道一致,再检查事件名和数据字段。
- 不要为了调试而把内部
api_address或appsecret暴露给浏览器、Postman 共享集合或公开日志。
浏览器端原则
- 访客端从
/visitor/data/get读取ws_address、appkey、visitor.channel。 - 客服端从
/agent/data/get读取实时配置,并订阅当前客服频道。 - 事件到达后以
mid去重;断线重连后重新订阅并拉取消息历史。 - 不要在浏览器请求中携带
appsecret、内部api_address或 PushApi 签名参数。