Skip to content

后端推送服务

本页只描述 Web 访客端、Web 客服端和 PHP 后端之间的推送。浏览器不应持有 appsecret,也不应直接调用 Socket 服务的内部 HTTP API。

配置关系

Socket 进程由 config/process.php 注册。它对外维护 WebSocket 连接,对内提供 HTTP 推送入口;app\service\Push 从数据库设置中读取 api_addressappkeyappsecret,并通过 PushApi 完成签名请求。

text
业务 Controller / Service

          │  Push::emit(channel, event, data)
          v
     app\service\Push
          │  内部 HTTP + 签名
          v
      Socket 进程
          │  WebSocket
          v
    浏览器订阅频道

Push 构造时从 setting 表读取以下配置。它们只属于后端运行环境:

设置用途安全要求
api_addressSocket 内部 HTTP 推送地址。仅允许应用服务器访问。
appkeySocket 应用标识。可随客户端初始化配置下发。
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.createdmessage.readconversation.ended
$data事件负载。不同事件使用不同字段,具体见“会话与消息事件”。
$result.status200 表示 Socket 服务接受推送;其他值表示推送失败。

频道约定

不要在业务 Controller 中手写频道格式。项目已有辅助方法用于访客与客服频道:

php
$visitorChannel = visitor_channel($bid, $uid);
$agentChannel = agent_channel($agentId);
$globalChannel = 'global-' . $bid;
频道接收者适合发送的事件
visitor-...当前访客的浏览器会话新消息、已读、撤回、会话结束、评分与解决状态。
agent-{agentId}指定客服的工作台新消息、输入中、转接、结束、隐藏和会话更新。
global-{bid}当前商户已连接的页面设置、客服在线状态、访客资料、上下文和标签定义变化。

消息写入后通常应同时推送访客频道与接待客服频道;只向一端推送会造成另一端页面不能实时更新。

事件设计要求

  1. 使用已存在的点分事件名,例如 message.createdmessage.readconversation.transferred;不要新增同义的横线或下划线事件名。
  2. 消息事件必须包含能定位服务端消息的 mid,并带上 uidagent_idauthorsub_typecontent 等实际需要的字段。
  3. Pushmessage.createdmessage.translated 会根据已落库消息补充标准化字段;应先写入数据库,再调用 emit()
  4. 全局频道使用补丁数据。只传发生改变的字段,接收端按字段合并。
  5. 事件负载不能包含密码、Session、Token、appsecret 或内部服务地址。

失败与一致性

status: 200 仅表示 Socket 服务已接受内部请求,不表示每个浏览器都已收到事件。因此数据一致性策略应为:

text
先提交业务数据

调用 Push::emit 发送增量通知

浏览器按 mid / 业务 ID 幂等合并

断线、失败或未知状态时由 HTTP 查询补齐

对关键业务操作,推送失败应记录服务端日志并保留已提交的业务结果;不要因为仅推送失败而回滚已经成功保存的消息或会话。客户端重连后的历史补拉是最终恢复机制。

开发调试

  1. 确认数据库 setting 中的 api_addressappkeyappsecret 与 Socket 进程配置一致。
  2. 在业务写入成功后检查 $result['status']$result['body']
  3. 浏览器确认订阅的频道与服务端目标频道一致,再检查事件名和数据字段。
  4. 不要为了调试而把内部 api_addressappsecret 暴露给浏览器、Postman 共享集合或公开日志。

浏览器端原则

  • 访客端从 /visitor/data/get 读取 ws_addressappkeyvisitor.channel
  • 客服端从 /agent/data/get 读取实时配置,并订阅当前客服频道。
  • 事件到达后以 mid 去重;断线重连后重新订阅并拉取消息历史。
  • 不要在浏览器请求中携带 appsecret、内部 api_address 或 PushApi 签名参数。