服务端
支付推送和公众号几乎一样,请参考:公众号:服务端。
官方文档
内置事件处理器
SDK 内置了两个便捷方法以便于开发者快速处理支付推送事件:
$message
属性已经默认解密,可直接访问解密后的属性;成功状态 SDK 默认会返回 success, 你可以不用返回任何东西;
支付成功事件
🚨 切记:推送信息不一定靠谱,可能是伪造的,所以拿到推送通知,只取订单号等必要信息,其它信息忽略,拿订单号重新查询微信支付订单的最新状态再做处理。
📖 官方文档:支付结果通知 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
php
$server = $app->getServer();
$server->handlePaid(function (Message $message, \Closure $next) {
// $message->out_trade_no 获取商户订单号
// $message->payer['openid'] 获取支付者 openid
// 🚨🚨🚨 注意:推送信息不一定靠谱哈,请务必验证
// 建议是拿订单号调用微信支付查询接口,以查询到的订单状态为准
return $next($message);
});
// 默认返回 ['code' => 'SUCCESS', 'message' => '成功']
return $server->serve();
退款成功事件
📖 官方文档:退款结果通知 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_11.shtml
php
$server = $app->getServer();
$server->handleRefunded(function (Message $message, \Closure $next) {
// $message->out_trade_no 获取商户订单号
// $message->payer['openid'] 获取支付者 openid
return $next($message);
});
// 默认返回 ['code' => 'SUCCESS', 'message' => '成功']
return $server->serve();
🚨 注意:经网友发现官方仍存在使用 v2 模式的退款推送,所以如果你的退款逻辑有异常,请参考以下方式实现(需要配置 v2 API key):
网友反馈的问题:https://github.com/w7corp/easywechat/issues/2737 目前已知的情况是:微信商户平台填写的 API 回调地址,然后在商户平台手动处理退款的。
php
// 建议使用单独的路由处理退款!
$server = $app->getServer();
// 推送消息,已解密
// 结构参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=10
$message = $server->getReqeustMessage();
// 你的逻辑...
// 返回 SUCCESS 或者 FAIL 等其他状态
return new \Nyholm\Psr7\Response(
200, [],
\EasyWeChat\Kernel\Support\Xml::build([
'return_code' => 'SUCCESS',
'return_msg' => 'OK'
])
);
其它事件处理
以上便捷方法都只处理了成功状态,其它状态,可以通过自定义事件处理中间件的形式处理:
php
$server->with(function($message, \Closure $next) {
// $message->event_type 事件类型
return $next($message);
});
自助处理推送消息
你可以通过下面的方式获取来自微信服务器的推送消息:
php
$message = $server->getRequestMessage();
$message
为一个 EasyWeChat\Pay\Message
实例。
你可以在处理完逻辑后自行创建一个响应,当然,在不同的框架里,响应写法也不一样,请自行实现。
回调消息
微信推送的回调消息是默认密文的,可参考文档,但是 SDK 已经帮你解密好了,所以以上例子中的 $message
默认访问的属性都是明文的,例如:
json
{
"transaction_id":"1217752501201407033233368018",
"amount":{
"payer_total":100,
"total":100,
"currency":"CNY",
"payer_currency":"CNY"
},
"mchid":"1230000109",
"trade_state":"SUCCESS",
"bank_type":"CMC",
"promotion_detail":[...],
"success_time":"2018-06-08T10:34:56+08:00",
"payer":{
"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
},
"out_trade_no":"1217752501201407033233368018",
"appid":"wxd678efh567hg6787",
"trade_state_desc":"支付成功",
"trade_type":"MICROPAY",
"attach":"自定义数据",
"scene_info":{
"device_id":"013467007045764"
}
}
所以你可以直接使用 $message->transaction_id
或者 $message['transaction_id']
来访问以上属性。
怎么获取密文属性呢?
$message
对象提供了 $message->getOriginalAttributes()
来获取加密前的数据:
json
{
"id": "EV-2018022511223320873",
"create_time": "2015-05-20T13:29:35+08:00",
"resource_type": "encrypt-resource",
"event_type": "TRANSACTION.SUCCESS",
"summary": "支付成功",
"resource": {
"original_type": "transaction",
"algorithm": "AEAD_AES_256_GCM",
"ciphertext": "",
"associated_data": "",
"nonce": ""
}
}
当然我们还特别封装了用于获取事件类型的方法:
php
$message->getEventType(); // TRANSACTION.SUCCESS