5.2 KiB
腾讯 IM 单聊消息即时归档回调
接收地址为 POST https://<业务域名>/api/im/messageNotify。接口调用 DiagnosisLogic::archiveImCallbackMessage(array $payload): int,归档成功、幂等重复或业务层安全忽略均返回腾讯原生应答:
{"ActionStatus":"OK","ErrorCode":0,"ErrorInfo":""}
归档抛异常时返回 HTTP 500 与 ActionStatus=FAIL,不会在写库失败时返回成功。错误响应和日志均不包含消息正文、签名、Token 或数据库异常内容。
部署配置
在服务端 .env 配置以下区段;鉴权 Token 应与腾讯 IM 控制台填写的值完全相同,以下内容仅为占位说明:
[IM]
CALLBACK_TOKEN = "在部署时填入独立生成的回调鉴权Token"
加载路径是 server/config/im.php → env('im.callback_token', '')。本项目 ThinkPHP Env 也支持进程环境变量 PHP_IM_CALLBACK_TOKEN。Token 为空或只有空白时接口返回 HTTP 503,拒绝全部回调;不会降级为免签名。部署后按既有流程刷新配置缓存和 PHP 常驻进程。
应用 ID 与现有 project.trtc.sdkAppId 配置一致(来自既有 [TRTC] SDK_APP_ID)。只核对 IM/TRTC 应用 ID,无需把 TRTC SecretKey 放入回调 URL 或这个配置文件。
腾讯 IM 控制台进入当前应用的“回调配置”:
- 填写上述 HTTPS 回调 URL,并开启回调。
- 勾选 发单聊消息之后回调,对应
C2C.CallbackAfterSendMsg。该事件可实时同步客户端或 REST API 单聊消息。腾讯官方单聊回调文档 - 在回调 URL 的配置中开启鉴权,填写与
[IM] CALLBACK_TOKEN相同的 Token。腾讯会追加Sign与RequestTime参数;签名算法为sha256(Token + RequestTime),时间偏差不得超过一分钟。腾讯官方鉴权说明 - 如需超时补投,开启事件发生之后回调的超时重试选项;这类回调默认不重试。官方默认回调超时为 2 秒,应监测归档耗时。失败回包不等同于已开启或保证重试,需结合控制台重试设置与历史拉取补偿。腾讯官方回调超时说明
部署只需新增接口与配置,不需要为患者添加登录 Token。自动控制器路由已支持 /api/im/messageNotify;API InitMiddleware 正常实例化控制器,LoginMiddleware 仅对 ImController/messageNotify 跳过用户会话查找,随后由控制器强制腾讯签名校验。其他 API 的登录要求不变。服务本身仍需满足项目原有安装与 HTTPS 入口条件。
接口校验与失败响应
- 只接受真实 POST 方法,不能通过方法覆盖头把 GET 伪装成 POST。
- 正文最大 1 MiB;检查 Content-Length 及实际正文长度,JSON 必须是对象,最大解析深度 64。
SdkAppid必须与配置一致;Sign 使用恒定时间hash_equals比较,签名时间窗口为正负 60 秒。- 请求正文必须有字符串
CallbackCommand;URL 中存在同名命令时必须完全相同。 - 其他已经通过鉴权、命令一致的回调返回 OK 并忽略,不会进入患者归档。
- HTTP 400 表示 JSON 或命令无效,403 表示鉴权失败,405 表示请求方法错误,413 表示正文超限,503 表示鉴权配置缺失,500 表示归档失败。
网关或 Web 服务器访问日志应对这个路径省略查询参数,避免默认 $request_uri 日志记录 URL 中的 Sign;应用代码只输出固定归档失败标记。正文内的患者/医生匹配与幂等规则由 archiveImCallbackMessage 负责。
虚构 curl 示例(未执行)
以下域名使用保留的 .invalid 后缀,Token、账户、消息和应用 ID 全是虚构值,只演示参数形状。不要将此示例直接指向生产环境。
DEMO_TOKEN='fictional-example-token'
REQUEST_TIME=$(date +%s)
SIGN=$(printf '%s' "${DEMO_TOKEN}${REQUEST_TIME}" | sha256sum | cut -d ' ' -f 1)
curl --request POST \
"https://im-callback.example.invalid/api/im/messageNotify?SdkAppid=1400000000&CallbackCommand=C2C.CallbackAfterSendMsg&RequestTime=${REQUEST_TIME}&Sign=${SIGN}" \
--header 'Content-Type: application/json' \
--data '{"CallbackCommand":"C2C.CallbackAfterSendMsg","From_Account":"patient_1001","To_Account":"doctor_2001","MsgSeq":7,"MsgRandom":8,"MsgTime":1700000000,"MsgKey":"7_8_1700000000","SendMsgResult":0,"MsgBody":[{"MsgType":"TIMTextElem","MsgContent":{"Text":"虚构测试消息"}}]}'
验证结果
php server/tests/ImCallbackTest.php:81 项断言通过,使用真实控制器、ThinkPHP Request/Json 与 LoginMiddleware,归档逻辑、配置和日志由内存替身替代。覆盖官方签名样例、正负一分钟边界、缺失配置、错误 App ID、伪造签名、命令一致性、JSON 结构、正文上限、无登录回调、写库及日志失败、幂等返回 0,以及其他 action 不能借用回调免登录分支。
新增控制器、签名服务、配置、中间件和测试 PHP 语法检查通过;修改文件 git diff --check 通过。测试使用虚构配置,不加载真实 .env,未连接业务数据库,也没有调用腾讯 API 或修改腾讯控制台。