PHP实现微信小程序支付的帮助类

46次阅读

共计 15626 个字符,预计需要花费 40 分钟才能阅读完成。

背景
事先准备工作

申请一个小程序,并开通微信支付,详细见:微信小程序支付业务说明

仔细查阅微信支付官方文档,详细见: 微信支付开发者文档

仔细阅读 微信支付统一下单接口

仔细阅读 支付结果通知接口

整理并在商户平台设置好相应的回掉地址,比如 http://test.dev.com/wechat/pa…

服务端编写两个接口 1) 微信预支付接口,http://test.dev.com/wechat/pr… , 以商品订单为例,此接口接受两个参数,goods_id 和 uid ,goods_id 表示商品编号,uid 表示用户编号,返回参数如下

{
errcode: 200,
msg: “SUCCESS”,
data: {
status: 1, // 状态,为 1 表示成功,其他的表示失败
result: “success”,
data: {
appId: “xxx”, // 小程序的 appid
timeStamp: 1545909092, // 时间戳
nonceStr: “vuryhptlafvpee92pxhji6zs5jl2n0gu”, // 随机串
package: “prepay_id=wx27191130962951f060bfa1323531879649”, // 支付的包参数
signType: “MD5”, // 签名方式
paySign: “B04272BB9BBDB1F52863D3B0EF580BE8″ // 支付签名
}
}
}
2) 微信支付回调接口,http://test.dev.com/wechat/pa…,此接口最好是 get 和 post 都设置,因为 微信在进行回调的时候会以 post 的形式进行请求
5. 建表 1) 商品订单表 (shop_goods_order),其中重要的字段有 out_trade_no,out_trade_no 传递给微信支付的支付订单号,也是我们自己的系统与微信对接的订单唯一标识;bill_no 表示微信支付的交易订单号,这个字段只有在订单支付成功之后进行更新,该字段也是查询位置支付订单的唯一标识,详细的表结构如下
CREATE TABLE `shop_goods_order` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`uid` int(10) DEFAULT ‘0’ COMMENT ‘ 用户编号 ’,
`goods_id` int(10) DEFAULT ‘0’ COMMENT ‘ 商品编号 ’,
`out_trade_no` varchar(30) DEFAULT ” COMMENT ‘ 订单序列号 ’,
`bill_no` varchar(30) DEFAULT ” COMMENT ‘ 支付方返回的交易订单号 ’,
`paid_money` int(10) DEFAULT ‘0’ COMMENT ‘ 支付的金额 ’,
`paid_integral` int(10) DEFAULT ‘0’ COMMENT ‘ 支付的健康币 ’,
`paid_type` varchar(15) DEFAULT ‘WXPAY’ COMMENT ‘ 支付类型,有 WXPAY 和 INTEGRAL 等值 ’,
`paid_status` varchar(10) DEFAULT ‘CHECKED’ COMMENT ‘ 支付状态,CHECKED 表示初始状态,SUCC 表示支付成功,FAILED 表示支付失败,REFUND 表示已退款 ’,
`add_time` int(10) DEFAULT ‘0’ COMMENT ‘ 添加时间 ’,
`paid_time` int(10) DEFAULT ‘0’ COMMENT ‘ 支付时间 ’,
`update_time` int(10) DEFAULT ‘0’ COMMENT ‘ 更新时间 ’,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
2) 商品信息表 (shop_goods_info),字段如下
CREATE TABLE `shop_goods_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘ 主键 ’,
`name` varchar(100) DEFAULT ” COMMENT ‘ 商品名称 ’,
`note` varchar(300) DEFAULT ” COMMENT ‘ 商品描述 ’,
`market_price` int(10) DEFAULT ‘0’ COMMENT ‘ 原价 ’,
`sale_price` int(10) DEFAULT ‘0’ COMMENT ‘ 售价 ’,
`integral` int(8) DEFAULT ‘0’ COMMENT ‘ 健康币 ’,
`main_thumbnail` varchar(40) DEFAULT ” COMMENT ‘ 主图 ’,
`thumbnail1` varchar(40) DEFAULT ” COMMENT ‘ 缩略图 1 ’,
`thumbnail2` varchar(40) DEFAULT ” COMMENT ‘ 缩略图 2 ’,
`thumbnail3` varchar(40) DEFAULT ” COMMENT ‘ 缩略图 3 ’,
`thumbnail4` varchar(40) DEFAULT ” COMMENT ‘ 缩略图 4 ’,
`thumbnail5` varchar(40) DEFAULT ” COMMENT ‘ 缩略图 5 ’,
`content` text COMMENT ‘ 详细介绍 ’,
`add_time` int(10) DEFAULT ‘0’ COMMENT ‘ 添加时间 ’,
`update_time` int(10) DEFAULT ‘0’ COMMENT ‘ 更新时间 ’,
`is_online` tinyint(1) DEFAULT ‘1’ COMMENT ‘ 商品是否上线 ’,
`sort` int(4) DEFAULT ‘0’ COMMENT ‘ 排序值,越大越靠前 ’,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
实现步骤
业务实现时序图

实现步骤说明
客户端

客户端调用 微信预支付接口 获取对应的微信支付参数
获取基础的支付参数后,调用 wx.requetPayment 接口调起微信支付
用户输入密码完成支付

服务端

客户端在发起支付前先往商品订单表里面创建一条订单,并生成对应的 out_trade_no 参数
调用微信支付的统一下单接口 https://api.mch.weixin.qq.com…,向微信发起支付订单请求,统一下单接口文档地址,见微信支付统一下单接口

支付请求结束后微信将支付结果返回给 微信支付回调接口

若支付成功,服务端将订单的 paid_status 字段设置 succ,并将 bill_no、paid_time、update_time 更新,bill_no 的值为微信支付的 transaction_id;若支付失败,将 paid_status 字段更新为 failed,并更新 update_time 字段

关键代码
客户端
发起微信支付
wxPay:function () {
var that = this
var params = {
goods_id: that.data.goods_id,
uid: that.data.uid,
paid_type: ‘WXPAY’
}

var param = JSON.stringify(params)
console.log(param)
param = app.Encrypt(param)
var url = app.data.API_DOMAIN + “/wechat/prepay?param=” + param
wx.showModal({
title: ‘ 提示 ’,
content: ‘ 确定要微信支付购买此系列课吗?’,
success(res) {
if (res.confirm) {
if (that.data.iswxpay == 0) {
that.setData({
iswxpay: 1
})
app.httpRequest(that.data.uid, url, function (response) {
var payinfo = response.data.data.data
wx.requestPayment({
timeStamp: payinfo.timeStamp.toString(),
nonceStr: payinfo.nonceStr,
package: payinfo.package,
signType: ‘MD5’,
paySign: payinfo.paySign,
success(res) {
wx.showToast({
title: ‘ 购买成功 ’,
icon: ‘success’
})
that.setData({
is_paid: 1
})
that.getSeminarInfo(that.data.sid, that.data.uid)
},
fail(res) {
that.setData({
iswxpay: 0
})
wx.showToast({
title: ‘ 购买失败 ’,
icon: ‘none’
})
}
})
console.log(response.data.data.data)
}, function (f_res) {}, function (f_res) {})
}
} else {
that.setData({
iswxpay: 0
})
console.log(‘ 取消微信支付 ’)
}
}
})
},
服务端
预支付接口关键代码
1、入口方法:orderPay
/**
* 微信支付的获取支付参数的接口
* 1. 先要用户编号和支付方式获取对应的订单,如果存在则取存在的,若不存在则创建,一种支付类型的订单值存在一条记录
* 2. 创建订单后根据 out_trade_no 来调用微信支付的统一下单接口得到微信支付的支付参数
* 3. 将参数返回给前端进行支付
* 4. 支付成功之后进行回掉
*/
public function orderPay($uid, $goodsId, $paidType){
$result = [];
$lockKey = BusinessHelper::getPayOrderLockRedisKey();
// 枷锁是为了防止并发
$this->doWithLock(function()use(&$result,$uid,$goodsId,$paidType){
error_log(‘$paidType ================>’.$paidType);
switch ($paidType){
case Constant::PAID_TYPE_MIXED :
error_log(‘doIntegralPay ================>’);
$result = $this->doMixedPay($uid,$goodsId,$paidType);
error_log(‘integral pay result ================>’.json_encode($result));
break;
case Constant::PAID_TYPE_WXPAY :
$result = $this->doWxaPay($uid,$goodsId,$paidType);
error_log(‘wx pay result ================>’.json_encode($result));
break;
}
},$lockKey,5);
error_log(‘result ================>’.json_encode($result));
return $result;
}

2、微信核心支付方法:doWxaPay
/**
* 通过小程序支付的逻辑
* @param $uid 用户编号
* @param $goodsId 系列课编号
* @param $paidType 支付类型,有 INTEGRAL 和 WXPAY 两种
* @return array
*/
public function doWxaPay($uid, $goodsId, $paidType){
$goodsInfo = ShopGoodsInfoService::getById($goodsId);
if(!$goodsInfo){
return [
‘status’ => -1,
‘result’ => ‘ 商品已经下架或者不存在 ’
];
}
$config = BusinessHelper::getWechatPayConfig();
$payHelper = new WechatPayHelper($config);
$payContent = $this->getWxaPrepayContent($uid,$paidType,$goodsId);
$params = $payHelper->prepay($payContent);
error_log(‘param ==============>’.json_encode($params));
return $params;
}
3、创建订单方法:createOrder 这个方法是为了建立订单,为了保证表示每一次支付都建立一个订单,我这边做两重的订单复用,先根据订单状态去查询是否有待支付的订单,如果有在判断这个订单的差功能键时间是否已经超过 7 天,如果超过七天则另外创建新的订单,尽最大的进行数据复用
/**
* 创建和验证订单,接口方法
* @param $uid 用户编号
* @param $paidType 支付类型
* @param $goodsId 系列课编号
* @return array
*/
protected function createOrder($uid, $paidType, $goodsId){
$existOrder = $this->getUserGoodsOrderWithPaidType($uid,$paidType,$goodsId);
if(!$existOrder){
return $this->generateOrder($uid,$paidType,$goodsId);
}
// 验证 7 天之类订单有效
$createTime = date(‘Y-m-d’,$existOrder[‘add_time’]);
$today = date(‘Y-m-d’);
$diff = TimeHelper::getDiffBetweenTwoDays($today,$createTime);
if($diff > 7){
return $this->generateOrder($uid,$paidType,$goodsId);
}
return $existOrder;
}
4、订单查重方法:getUserGoodsOrderWithPaidType
/**
* 根据支付类型获取用户对应的商品的订单
*/
public function getUserGoodsOrderWithPaidType($uid, $paidType, $goodsId){
$order = BeanHelper::convertStdClsToArr(
ShopGoodsOrder::where(‘uid’, $uid)
->where(‘goods_id’,$goodsId)
->where(‘paid_type’,$paidType)
->whereIn(‘paid_status’,[Constant::PAID_STATUS_CHECKED])
->orderBy(‘add_time’,’desc’)
->first()
);
return $order;
}
5、生成订单方法:
/**
* 生成订单,辅助方法
* @param $uid 用户编号
* @param $paidType 支付类型
* @param $goodsId 系列课编号
* @return array
*/
public function generateOrder($uid, $paidType, $goodsId){
$goodsInfo = ShopGoodsInfoService::getById($goodsId);
$priceKey = $paidType == Constant::PAID_TYPE_WXPAY ? ‘market_price’ : ‘sale_price’;
$price = formatArrValue($goodsInfo,$priceKey,0);
$integral = $paidType == Constant::PAID_TYPE_WXPAY ? 0 : formatArrValue($goodsInfo,’integral’,0);
$baseMeasureUnit = 100;
$insertOrderData = [
‘uid’ => $uid,
‘goods_id’ => $goodsId,
‘out_trade_no’ => BusinessHelper::generateOutTradeNo(Constant::PAID_SCENE_SHOP_GOODS_ORDER),
‘paid_money’ => $price * $baseMeasureUnit,
‘paid_integral’ => $integral,
‘paid_type’ => $paidType,
‘paid_status’ => Constant::PAID_STATUS_CHECKED,
‘add_time’ => time(),
‘update_time’ => time(),
];
$existOrder = BeanHelper::convertStdClsToArr($this->store($insertOrderData));
return $existOrder;
}
6、生成 outTradeNo 方法这个方法中的 getPaidSceneMapping 方法返回的是一个数组,out_trade_no 方法有 3 个部分组成,分别是当前时间,场景值(这个是为了保证不同的支付场景对应的不同的业务代码)以及 10 位随机数字组成
/**
* 生成第三方支付的外部订单号
*/
public static function generateOutTradeNo($paidScene = Constant::PAID_SCENE_SEMINAR_ORDER){
$prefix = date(‘YmdHis’);
$paidSceneMap = self::getPaidSceneMapping();
$scene = formatArrValue($paidSceneMap,$paidScene,’0001′);
$suffix = generateRandomNum(10);
return $prefix.$scene.$suffix;
}

/**
* 获取支付场景的 map,这个是为了区分不同的支付场景时候更新不同的业务字段,为了拓展进行的预留
*/
public static function getPaidSceneMapping(){
return [
Constant::PAID_SCENE_SEMINAR_ORDER => ‘0001’,
Constant::PAID_SCENE_SHOP_GOODS_ORDER => ‘0002’
];
}

支付回调接口关键代码
入口方法:payNotify
/**
* 支付的回掉
*/
public function payNotify(Request $request){
error_log(‘notify request param ========>’);
$config = BusinessHelper::getWechatPayConfig();
$helper = new WechatPayHelper($config);
$result = $helper->notify($request);
return $result;
}
微信支付帮助类
<?php

namespace App\Http\Helper\Pay;
use App\Http\Helper\Jz\BusinessHelper;
use App\Http\Helper\Jz\Constant;
use App\Http\Helper\LogHelper;
use SeminarOrderService;
use ShopGoodsOrderService;
/**
* Created by PhpStorm.
* User: Auser
* Date: 2018/12/17
* Time: 15:41
*/
class WechatPayHelper {

public $config;
public function __construct($config)
{
$this->config = $config;
}

/**
* 预支付请求接口 (POST)
* 返回 json 的数据
*/
public function prepay($payContent)
{
$config = $this->config;
$unifiedorder = [
‘appid’ =>$config[‘appid’],
‘mch_id’ =>$config[‘mchid’],
‘nonce_str’ =>self::getNonceStr(),
‘body’ =>$payContent[‘body’],
‘out_trade_no’ =>$payContent[‘out_trade_no’],
‘total_fee’ =>$payContent[‘fee’],
‘spbill_create_ip’=>$_SERVER[‘REMOTE_ADDR’],
‘notify_url’ =>$config[‘notify_url’],
‘trade_type’ =>’JSAPI’,
‘openid’ =>$payContent[‘openid’]
];
error_log(‘config ===============>’.json_encode($config));
$unifiedorder[‘sign’] = $this->makeSign($unifiedorder);
error_log(‘unifine order param ===============>’.json_encode($unifiedorder));
// 请求数据
$xmldata = $this->array2xml($unifiedorder);
$url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder’;
$res = $this->request($url, $xmldata);
if(!$res){
return $this->errorResult(“Can’t connect the server”);
}
$content = $this->xml2array($res);
error_log(‘unifine order result ===============>’.json_encode($content));
if(strval($content[‘result_code’]) == ‘FAIL’){
return $this->errorResult(strval($content[‘return_msg’]));
}
if(strval($content[‘return_code’]) == ‘FAIL’){
return $this->errorResult(strval($content[‘return_msg’]));
}
// 拼接小程序的接口数据
$resData = [
‘appId’ => strval($content[‘appid’]),
‘timeStamp’ => time(),
‘nonceStr’ => $this->getNonceStr(),
‘package’ => ‘prepay_id=’.strval($content[‘prepay_id’]),
‘signType’ => ‘MD5’
];
// 加密签名
$resData[‘paySign’] = $this->makeSign($resData);
return $this->successResult($resData);
}

/**
* @return array|bool
* 微信支付回调验证
* 返回数据
*/
public function notify(){
//$xml = $GLOBALS[‘HTTP_RAW_POST_DATA’];
error_log(“wechat pay notify message ============>”);
$xml = file_get_contents(‘php://input’);
// 将服务器返回的 XML 数据转化为数组
$data = $this->xml2array($xml);
// 保存微信服务器返回的签名 sign
$dataSign = $data[‘sign’];
// sign 不参与签名算法
unset($data[‘sign’]);
$sign = $this->makeSign($data);
// 判断签名是否正确 判断支付状态
$result = false;
error_log(“return data ============>”.json_encode($data));
// 验证订单是否已经支付,调用订单查询接口
$isPayment = $this->verifyPament($data);
error_log(“isPayment ============>”.$isPayment);
if($isPayment && ($data[‘return_code’]==’SUCCESS’) && ($data[‘result_code’]==’SUCCESS’)) {
error_log(“isPayment success============>”);
$outTradeNo = $data[‘out_trade_no’];
$concurrentTime = 30;
$lockKey = getCacheKey(‘redis_key.cache_key.zset_list.lock’) . $outTradeNo;
// 采用并发锁控制并发
SeminarOrderService::doWithLock(function()use(&$result , $data){
$result = $data;
$this->setPaidSuccess($data);
},$lockKey,$concurrentTime);
}else{
error_log(“isPayment failed============>”);
$this->setPaidFail($data);
}
// 返回状态给微信服务器
if($result){
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>’;
}else {
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ 签名失败]]></return_msg></xml>’;
}
return $str;
}

/**
* 支付成功
*/
public function setPaidSuccess($data){
error_log(‘current paid data =============>’.json_encode($data));
$paidType = substr($data[‘out_trade_no’], 14, 4);
error_log(‘current paid type is =============>’.$paidType);
switch ($paidType){
case ‘0001’ :
SeminarOrderService::setOrderPaid($data);
break;
case ‘0002’:
ShopGoodsOrderService::setOrderPaid($data);
break;
}
}

/**
* 支付失败
*/
public function setPaidFail($data){
$paidType = intval(substr($data[‘out_trade_no’], 14, 4));
LogHelper::info(‘current paid type is =============>’.$paidType);
switch ($paidType){
case ‘0001’ :
SeminarOrderService::setOrderPaidFailed($data);
break;
case ‘0002’:
ShopGoodsOrderService::setOrderPaidFailed($data);
break;
}
}

/**
* 验证支付的问题
*/
public function verifyPament($wxPayResp){
error_log(“verify paymnent method=======>”.json_encode($wxPayResp));
$url = “https://api.mch.weixin.qq.com/pay/orderquery”;
// 检测必填参数
if(!$wxPayResp[‘transaction_id’] && !$wxPayResp[‘out_trade_no’]) {
error_log(“ 订单查询接口中,out_trade_no、transaction_id 至少填一个!”);
return false;
}
error_log(“ 开始查询 ==============》接口 ”);
$config = BusinessHelper::getWechatPayConfig();
error_log(“post config ==============》”.json_encode($config));
error_log(“transaction is===============>”.$wxPayResp[‘transaction_id’]);
error_log(“appid is===============>”.$config[‘appid’]);
error_log(“transaction is===============>”.$config[‘mchid’]);
error_log(“nonce_string is===============>”.$this->getNonceStr());
$params = [
‘appid’ => $config[‘appid’],
‘mch_id’ => $config[‘mchid’],
‘nonce_str’ => $this->getNonceStr(),
‘transaction_id’ => $wxPayResp[‘transaction_id’]
];
error_log(“post PARAM without sign==============》”);
$params[‘sign’] = $this->makeSign($params);
error_log(“post PARAM0 with sign ==============》”);
$xmlData = $this->array2xml($params);
$response = $this->request($url,$xmlData);
if(!$response){
error_log(“ 接口请求错误:”);
return false;
}
$result = $this->xml2array($response);
error_log(“ 查询订单接口返回结果:”.json_encode($result));
if(array_key_exists(“return_code”, $result)
&& array_key_exists(“trade_state”, $result)
&& $result[“return_code”] == “SUCCESS”
&& $result[“trade_state”] == “SUCCESS”){
return true;
}
return false;
}

//————————————————————— 用到的函数 ————————————————————
/**
* 错误返回提示
* @param string $errMsg 错误信息
* @param string $status 错误码
* @return array json 的数据
*/
protected function errorResult($errMsg = ‘error’, $status = Constant::PAID_RESULT_FAILED)
{
return [
‘status’=>$status,
‘result’=>’fail’,
‘data’=>$errMsg
];
}

/**
* 正确返回
* @param array $data 要返回的数组
* @return array json 的数据
*/
protected function successResult($data=[]){
return [
‘status’=> Constant::PAID_RESULT_SUCCESS,
‘result’=>’success’,
‘data’=>$data
];
}

/**
* 将一个数组转换为 XML 结构的字符串
* @param array $arr 要转换的数组
* @param int $level 节点层级, 1 为 Root.
* @return string XML 结构的字符串
*/
protected function array2xml($arr, $level = 1){
$s = $level == 1 ? “<xml>” : ”;
foreach($arr as $tagname => $value) {
if (is_numeric($tagname)) {
$tagname = $value[‘TagName’];
unset($value[‘TagName’]);
}
if(!is_array($value)) {
$s .= “<{$tagname}>”.(!is_numeric($value) ? ‘<![CDATA[‘ : ”).$value.(!is_numeric($value) ? ‘]]>’ : ”).”</{$tagname}>”;
}else {
$s .= “<{$tagname}>” . $this->array2xml($value, $level + 1).”</{$tagname}>”;
}
}
$s = preg_replace(“/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/”, ‘ ‘, $s);
return $level == 1 ? $s.”</xml>” : $s;
}

/**
* 将 xml 转为 array
* @param string $xml xml 字符串
* @return array 转换得到的数组
*/
protected function xml2array($xml)
{
// 禁止引用外部 xml 实体
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, ‘SimpleXMLElement’, LIBXML_NOCDATA)), true);
return $result;
}

/**
*
* 产生随机字符串,不长于 32 位
* @param int $length
* @return 产生的随机字符串
*/
protected function getNonceStr($length = 32){
$chars = “abcdefghijklmnopqrstuvwxyz0123456789″;
$str =””;
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}

/**
* 生成签名
* @return 签名
*/
protected function makeSign($data){
// 获取微信支付秘钥
$key = $this->config[‘mch_secret’];
// 去空
$data = array_filter($data);
// 签名步骤一:按字典序排序参数
ksort($data);
$signParam = http_build_query($data);
$signParam = urldecode($signParam);
// 签名步骤二:在 string 后加入 KEY
$signContent = $signParam.”&key=”.$key;
// 签名步骤三:MD5 加密
$sign = md5($signContent);
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
}

/**
* 微信支付发起请求
*/
protected function request($url, $xmldata, $second=30, $aHeader=array()){
$ch = curl_init();
// 超时时间
curl_setopt($ch,CURLOPT_TIMEOUT,$second);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
// 这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, ‘10.206.30.98’);
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
if(count($aHeader) >= 1 ){
curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$xmldata);
$data = curl_exec($ch);
if($data){
curl_close($ch);
return $data;
}
else {
$error = curl_errno($ch);
echo “call faild, errorCode:$error\n”;
curl_close($ch);
return false;
}
}

}
踩坑点
1、支付回调接口 http://test.dev.com/wechat/pa… 一定要设置成 get、post 都能访问, 我当初只设置了 get 请求可以访问,浪费了好多时间进行排查,而微信回调的数据基本都是以 post 形式进行调用的

正文完
 0