# 腾讯 IM 单聊消息即时归档回调 接收地址为 `POST https://<业务域名>/api/im/messageNotify`。接口调用 `DiagnosisLogic::archiveImCallbackMessage(array $payload): int`,归档成功、幂等重复或业务层安全忽略均返回腾讯原生应答: ```json {"ActionStatus":"OK","ErrorCode":0,"ErrorInfo":""} ``` 归档抛异常时返回 HTTP 500 与 `ActionStatus=FAIL`,不会在写库失败时返回成功。错误响应和日志均不包含消息正文、签名、Token 或数据库异常内容。 ## 部署配置 在服务端 `.env` 配置以下区段;鉴权 Token 应与腾讯 IM 控制台填写的值完全相同,以下内容仅为占位说明: ```ini [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 控制台进入当前应用的“回调配置”: 1. 填写上述 HTTPS 回调 URL,并开启回调。 2. 勾选 **发单聊消息之后回调**,对应 `C2C.CallbackAfterSendMsg`。该事件可实时同步客户端或 REST API 单聊消息。[腾讯官方单聊回调文档](https://cloud.tencent.com/document/product/269/2716) 3. 在回调 URL 的配置中开启鉴权,填写与 `[IM] CALLBACK_TOKEN` 相同的 Token。腾讯会追加 `Sign` 与 `RequestTime` 参数;签名算法为 `sha256(Token + RequestTime)`,时间偏差不得超过一分钟。[腾讯官方鉴权说明](https://cloud.tencent.cn/document/product/269/1522) 4. 如需超时补投,开启事件发生之后回调的超时重试选项;这类回调默认不重试。官方默认回调超时为 2 秒,应监测归档耗时。失败回包不等同于已开启或保证重试,需结合控制台重试设置与历史拉取补偿。[腾讯官方回调超时说明](https://cloud.tencent.cn/document/product/269/1522) 部署只需新增接口与配置,不需要为患者添加登录 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 全是虚构值,只演示参数形状。不要将此示例直接指向生产环境。 ```sh 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 或修改腾讯控制台。