QQ小程序里调用微信支付的问题,需要同时url带参数+post数据,我的返回结果是 401 Unauthorized {}
hetao29 opened this issue · comments
HeTao commented
运行环境
- OS:Linux
- PHP:7.4.27
- wechatpay-php:1.4.5
描述你的问题现象
如果在post一个url的时候,同时带上query和post的body,文档如下:https://q.qq.com/wiki/develop/miniprogram/server/virtual-payment/wx_pay.html
$url = "https://api.q.qq.com/wxpay/v3/pay/partner/transactions/h5";
$headers = [
'Accept' => 'application/json' ,
"Content-Type"=>"application/json, charset=UTF-8",
];
$resp = $this->_instance->chain($url)->post([
'query'=> [
"appid"=>$qq_appid,
"access_token"=>$conf['access_token'],
"real_notify_url"=>$real_notify_url,
],
'body' => $body,
'headers' => $headers,
]);
James ZHANG commented
看了下文档,其中:
- 注意事项
- 微信支付 V3 版 API 的签名信息包含了 URL,这里签名时应使用微信支付原版 URL。不要携带 appid, access_token, real_notify_url 这些参数。
- 如H5下单API(直连模式) 下,参与签名的 URL 应为
/v3/pay/transactions/h5
- 如H5下单API(直连模式) 下,参与签名的 URL 应为
- 微信支付 V3 版 API 的签名信息包含了 URL,这里签名时应使用微信支付原版 URL。不要携带 appid, access_token, real_notify_url 这些参数。
- QQ小程序后台仅对统一下单和支付回调两种接口进行透明转发。建议先直接请求微信支付后台调试接口,待接口调试成功后再转到QQ小程序后台代理接口。
需要做自定义签名signer
适配,代码就如下
use GuzzleHttp\Middleware;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
$qProxySigner = function (RequestInterface $request) use ($merchantId, $merchantSerial, $merchantPrivateKey): string {
$nonce = Formatter::nonce();
$timestamp = (string) Formatter::timestamp();
$signature = Rsa::sign(Formatter::request(
$request->getMethod(),
\str_ireplace('/wxpay', '', $request->getUri()->getPath()),
$timestamp,
$nonce,
(string) $request->getBody()
), $merchantPrivateKey);
return $request->withHeader('Authorization', Formatter::authorization(
$merchantId,
$nonce,
$signature,
$timestamp,
$merchantSerial
));
};
$stack = $instance->getDriver()->select()->getConfig('handler');
// 卸载SDK内置签名中间件
$stack->remove('signer');
// 注册适配q.qq.com下的支付的请求签名中间件
$stack->before('prepare_body', Middleware::mapRequest(
static function (RequestInterface $request) use ($qProxySigner): RequestInterface {
return $request->withHeader('Authorization', $qProxySigner($request));
}
), 'signer');
// 然后正常chainable请求即可
$resp = $this->_instance->chain('v3/pay/partner/transactions/h5')->post([
'base_uri' => 'https://api.q.qq.com/wxpay/',
'query' => [
"appid"=>$qq_appid,
"access_token"=>$conf['access_token'],
"real_notify_url"=>$real_notify_url,
],
]);
James ZHANG commented
或者直接用QQ小程序支持的微信支付APIv2
接口,代码无需做适配即可使用,如下:
$resp = $this->_instance->chain('v2/wxpay/unifiedorder')->post([
'base_uri' => 'https://api.q.qq.com/',
'query' => [
'appid' => $qq_appid,
'access_token' => $conf['access_token'],
'real_notify_url' => $real_notify_url,
],
'xml' => [
'version' => '1.0',
'profit_sharing' => 'N',
'appid' => 'wxd678efh567hg6787',
'mch_id' => '1230000109',
'device_info' => '013467007045764',
'sign_type' => 'MD5',
'body' => '腾讯充值中心-QQ会员充值',
'detail' => '{"cost_price":1,"receipt_id":"wx123","goods_detail":[{"goods_id":"商品编码","wxpay_goods_id":"1001","goods_name":"iPhone6s 16G","quantity":1,"price":1},{"goods_id":"商品编码","wxpay_goods_id":"1002","goods_name":"iPhone6s 32G","quantity":1,"price":1}]}',
'attach' => '深圳分店',
'out_trade_no' => '20150806125346',
'fee_type' => 'CNY',
'total_fee' => '88',
'spbill_create_ip' => '123.12.12.123',
'time_start' => '20091225091010',
'time_expire' => '20091227091010',
'goods_tag' => 'WXG',
'notify_url' => 'http://www.weixin.qq.com/wxpay/pay.php',
'trade_type' => 'MWEB',
'product_id' => '12235413214070356458058',
'limit_pay' => 'no_credit',
'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o',
'receipt' => 'Y',
'scene_info' => '{"store_info" : {"id": "SZTX001","name": "腾大餐厅","area_code": "440305","address": "科技园中一路腾讯大厦" }}',
],
]);
HeTao commented
最后我实现的方式,是使用 GuzzleHttp的原生Client
use GuzzleHttp\Client;
$client = new Client();
$resp = $client->request('POST', $url, [
'query'=> [
"appid"=>$qq_appid,
"access_token"=>$conf['access_token'],
"real_notify_url"=>$real_notify_url,
],
'body' => $body,
'headers' => $headers,
]);