- 后端
- 即时通讯
【免费下载链接】easywechat
📦 一个 PHP 微信 SDK
EasyWeChat 6.x 的企业微信(EasyWeChat\Work)服务端模块封装了企业微信向开发者服务器推送消息的完整处理链路:从 URL 验证、消息加解密,到通讯录变更事件、批量任务事件等第三方平台推送事件的分发,再到智能机器人 JSON 消息的接收与回复。本文将以 企业微信服务端文档 为骨架,结合 Work/Server 源码 与 服务端测试用例 展开,帮你掌握$app->getServer()的完整用法,并在生产环境中正确接入企业微信回调。
服务端模块的获取与基本用法
与公众号一致,企业微信服务端模块通过Application工厂方法获取,默认情况下它会替你处理服务端验证(URL 校验)逻辑:
use EasyWeChat\Work\Application; $config = [ 'corp_id' => 'wx3cf0f39249eb0exx', 'secret' => 'f1c242f4f28f735d4687abb469072axx', 'token' => 'easywechat', 'aes_key' => '35d4687abb469072a29f1c242xxxxxx', // 记得配置suite_id,不然suite_ticket不能自动存储 'suite_id' => 'ww9f1388bf664xxxxx', 'suite_secret' => 'reuXvCX_5FhDVm_sOslJEHRVxxxxxxx', ]; $app = new Application($config); $server = $app->getServer();获取到$server后,直接把serve()的返回值返回给框架即可完成回调接入:
$response = $server->serve(); return $response;$response是一个Psr\Http\Message\ResponseInterface实现,具体如何适配取决于你所使用的框架;如果使用 ThinkPHP、Workerman 等框架,需要先把框架请求转换成 Symfony 请求,再通过$app->setRequestFromSymfonyRequest($symfonyRequest)替换请求对象。企业微信服务端推送的整体设计与公众号一致,公众号侧的详细用法(服务端验证、中间件模式、回复消息结构等)可参考 公众号:服务端,本篇文章重点展开企业微信特有的部分:第三方平台推送事件与内置消息处理器。
serve() 的完整处理流程:URL 验证、消息解密与响应
在 src/Work/Server.php 中,serve()按以下顺序处理请求:
- URL 验证:当请求查询参数中存在
echostr时,使用企业微信的Encryptor对echostr进行解密并直接返回明文,完成企业微信管理后台的回调 URL 校验。解密需要msg_signature、nonce、timestamp三个查询参数(对应代码 serve() 中的 echostr 分支)。 - 获取原始消息:通过
getRequestMessage()将请求体解析为EasyWeChat\Work\Message实例。 - 前置解密中间件:
prepend($this->decryptRequestMessage())把"消息解密"作为最先执行的中间件注册进去——它会读取msg_signature、timestamp、nonce,校验签名并解密出明文内容(见 decryptRequestMessage())。 - 执行开发者注册的中间件:
handle()依次调用所有中间件,若没有注册任何中间件,则返回默认的SUCCESS文本响应。 - 回复转换:如果中间件返回的不是
ResponseInterface,会根据messageType选择 XML 或 JSON 两种回复转换器:XML 由 RespondXmlMessage trait 负责(自动补齐ToUserName、FromUserName、CreateTime并做 AES 加密),JSON 由 RespondJsonMessage trait 负责。
对应地,tests/Work/ServerTest.php 中有三个典型测试佐证了这一流程:
test_it_will_handle_validation_request:带echostr的 GET 请求返回解密后的明文,完成 URL 验证;test_it_will_validate_message:带Encrypt密文节点的 POST 请求在签名校验、解密后返回SUCCESS;test_it_will_response_success_without_handlers:未注册任何中间件时同样返回SUCCESS。
企业微信消息体的签名校验与 AES 解密由Kernel\Traits\DecryptMessage提供:签名校验将token、timestamp、nonce、密文四者排序后做 SHA1,再通过hash_equals与msg_signature比对,校验失败会抛出BadRequestException(见 DecryptMessage trait)。企业微信的Encryptor基于corpId、token、aesKey构造,见 src/Work/Encryptor.php。
第三方平台推送事件:通讯录变更与批量任务
企业微信数据推送的典型场景是通讯录变更(change_contact)与批量任务执行完成(batch_job_result),事件及子类型如下:
| 事件(Event) | 子类型(ChangeType) | 含义 |
|---|---|---|
change_contact | create_user | 新增成员 |
change_contact | update_user | 更新成员 |
change_contact | delete_user | 删除成员 |
change_contact | create_party | 新增部门 |
change_contact | update_party | 更新部门 |
change_contact | delete_party | 删除部门 |
change_contact | update_tag | 成员标签变更 |
batch_job_result | — | 批量任务执行完成 |
SDK 将这些事件预置为一系列开箱即用的便捷处理器,你无需手动判断Event与ChangeType字段,直接注册对应回调即可。
内置消息处理器:通讯录变更与批量任务
处理通讯录变更事件(成员、部门、标签)
$server->handleContactChanged(function($message, \Closure $next) { // 通讯录发生任何变更时都会进入这里 return $next($message); });处理任务执行完成事件
$server->handleBatchJobsFinished(function($message, \Closure $next) { // 批量任务执行完成 return $next($message); });这些便捷方法在源码中的实现本质上是条件中间件:以 handleContactChanged() 为例,它通过with()注册一个闭包,仅当$message->Event === 'change_contact'时才调用你传入的回调,否则直接$next($message)把消息交给下一个中间件。而Message对象则通过@property声明暴露了Event、InfoType、MsgType、ChangeType等字段,见 src/Work/Message.php。
成员变更事件
// 新增成员 $server->handleUserCreated(function($message, \Closure $next) { // ... return $next($message); }); // 更新成员 $server->handleUserUpdated(function($message, \Closure $next) { // ... return $next($message); }); // 删除成员 $server->handleUserDeleted(function($message, \Closure $next) { // ... return $next($message); });部门变更事件
// 新增部门 $server->handlePartyCreated(function($message, \Closure $next) { // ... return $next($message); }); // 更新部门 $server->handlePartyUpdated(function($message, \Closure $next) { // ... return $next($message); }); // 删除部门 $server->handlePartyDeleted(function($message, \Closure $next) { // ... return $next($message); });成员标签变更事件
$server->handleUserTagUpdated(function($message, \Closure $next) { // ... return $next($message); });从源码可以看出这些处理器共用同一套匹配模式:Event === 'change_contact'且ChangeType等于对应值时才触发回调。例如 handleUserCreated() 匹配create_user,handlePartyCreated() 匹配create_party,handleUserTagUpdated() 匹配update_tag。测试用例test_it_will_respond_from_event_handlers也验证了在收到Event = change_contact的推送后,通过addEventListener('change_contact', ...)可以正确收到回调并回复消息。
智能机器人事件:JSON 消息的接收与回复
智能机器人推送的消息体是JSON 格式(而非 XML),因此在获取server对象时必须显式指定消息格式为json:
// 指定消息格式 JSON $server = $app->getServer(messageType: 'json'); // 获取解密后的机器人消息 $message = $server->getDecryptedMessage(); // 回复消息 $server->with(function($message, \Closure $next) { return [ 'msgtype' => 'stream', 'stream' => [ 'id' => 'id00001', 'finish' => true, 'content' => '信息已收到', ], ]; });这里的messageType参数对应 Application::getServer() 的构造参数,默认值为'xml';传入'json'后,serve()内的回复转换会走 transformJsonToReply(),并以application/json响应头输出。需要说明的是,JSON 回复要求返回的数组必须包含msgtype字段(见 normalizeJsonResponse()),否则会抛出InvalidArgumentException。关于智能机器人消息的具体字段与流式(stream)回复格式,请以企业微信官方「智能机器人」文档为准。
其它事件处理:自定义中间件
上面的便捷处理器只覆盖了特定事件。对于其它任何推送状态,都可以通过自定义中间件自行判断Event、ChangeType、MsgType等字段:
$server->with(function($message, \Closure $next) { // $message->Event 事件类型(如 change_contact、batch_job_result 等) // $message->ChangeType 变更子类型(如 create_user、update_party 等) return $next($message); });中间件由Kernel\Traits\InteractWithHandlers提供注册与调度能力,你可以链式注册多个中间件按顺序执行;如果在某个中间件内直接返回了回复内容(字符串或数组),后续中间件将不再执行,因此需要全局执行的逻辑应优先注册。回复消息时省略ToUserName、FromUserName、CreateTime等字段,SDK 会在 XML 转换时自动补齐并加密。
自助处理推送消息:原始消息与解密消息
如果你不想走中间件,也可以直接获取推送消息自行处理:
$message = $server->getRequestMessage(); // 原始消息获取解密后的消息(自 6.5.0 起支持):
$message = $server->getDecryptedMessage();$message是一个EasyWeChat\Work\Message实例(继承自Kernel\Message)。getDecryptedMessage()的实现位于 src/Work/Server.php:它先解析请求得到原始消息,再读取msg_signature、timestamp、nonce三个查询参数,调用DecryptMessage::decryptMessage()完成签名校验与 AES 解密,并把解密后的明文字段 merge 回消息对象,因此你拿到的$message可以直接读取事件字段。处理完业务逻辑后,你需要自行构造响应返回(不同框架的响应写法不同,请按你的框架实现)。
完整接入示例
下面是一个整合了 URL 验证、通讯录变更监听与智能机器人 JSON 回复的完整回调入口示例:
use EasyWeChat\Work\Application; $config = [ 'corp_id' => 'wx3cf0f39249eb0exx', 'secret' => 'f1c242f4f28f735d4687abb469072axx', 'token' => 'easywechat', 'aes_key' => '35d4687abb469072a29f1c242xxxxxx', 'suite_id' => 'ww9f1388bf664xxxxx', 'suite_secret' => 'reuXvCX_5FhDVm_sOslJEHRVxxxxxxx', ]; $app = new Application($config); $server = $app->getServer(); // XML 消息格式 // 1. 通讯录成员变更 $server->handleUserCreated(function($message, \Closure $next) { // 新成员入通讯录,例如同步到本地数据库 return $next($message); }); // 2. 部门变更 $server->handlePartyUpdated(function($message, \Closure $next) { // 部门信息更新 return $next($message); }); // 3. 其它事件兜底 $server->with(function($message, \Closure $next) { // 自定义逻辑 return $next($message); }); $response = $server->serve(); return $response;需要注意:不要在调用serve()前向客户端输出任何内容(包括 PHP 报错、BOM、调试输出),否则会导致企业微信回调验证失败。企业微信完整的配置项说明(http超时、重试、base_uri覆盖等)可参考 企业微信实例化与配置;服务端验证、中间件模式、回复消息结构等通用能力可进一步阅读 公众号:服务端。
- 后端
- 即时通讯
【免费下载链接】easywechat
📦 一个 PHP 微信 SDK
相关推荐
EasyWeChat 企业微信服务商(OpenWork)服务端:第三方推送事件处理与消息中间件实战指南
EasyWeChat 企业微信服务商(OpenWork)服务端:第三方推送事件处理与消息中间件实战指南 本篇技术指南以 EasyWeChat 6.x 的 Ope
后端即时通讯EasyWeChat 企业微信服务端接入指南:消息解密、事件回调与响应处理(4.x)
EasyWeChat 企业微信服务端接入指南:消息解密、事件回调与响应处理(4.x) 企业微信(Work WeChat)应用开启“接收消息”后,所有来自企业微信
后端即时通讯EasyWeChat 4.x 服务端开发完全指南:消息接收、事件处理与 XML 回复实战
EasyWeChat 4.x 服务端开发完全指南:消息接收、事件处理与 XML 回复实战 公众号开发的核心不在"调用接口",而在"接收消息"。微信服务器会把用户
后端即时通讯
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考