文章目录
一、APP微信支付
效果预览
1、微信支付之前就要生成自己的订单了,也就是存在自己服务器的订单。
//每个人的请求方式封装不一样,可忽略this.$u.api...
this.$u.api.submitOrder({
good_name: _that.bjInfo.name,
good_id: _that.bjInfo.id,
user_id: _that.userId,
address_id: _that.addressInfo.id,
total: _that.bjInfo.price,
paymethod: _that.isWechat ? 0 : 1,
buyType: _that.buyType,
}).then(res => {
console.log(res)
//这里自己的订单生成成功了,可以调用微信支付了,把下面的微信支付代码封装到一个方法里面在这里调用即可
//#endif
}).catch(err => {
this.$refs.uToast.show({
title: err.data.msg,
})
console.log(err)
})
console.log('微信支付')
//第一步调用后台微信支付接口,一般传参是三个out_trade_no、good_name、total_fee
//这个接口返回所有前端唤起微信支付的所有参数
/**前端需要的参数
let obj = {
appid: '',
noncestr: '',
package: '', // 固定值,以微信支付文档为主
partnerid: '',
prepayid: '',
timestamp: '',
sign: '' // 根据签名算法生成签名
};
**/
_that.$u.api.wxPay({
out_trade_no: order.out_trade_no,
good_name: order.good_name,
total_fee: order.total_fee,
}).then(res => {
console.log(res)
let obj = {
appid: res.data.appid,
noncestr: res.data.noncestr,
package: res.data.package, // 固定值,以微信支付文档为主
partnerid: res.data.partnerid,
prepayid: res.data.prepayid,
timestamp: res.data.timestamp,
sign: res.data.sign // 根据签名算法生成签名
};
let orderInfo = JSON.stringify(obj);
// console.log(orderInfo);
console.log(orderInfo);
uni.requestPayment({
provider: 'wxpay',
orderInfo: orderInfo, //微信、支付宝订单数据
success: res => {
_that.editOrderStatus(order);
},
fail: function(err) {
_that.$u.route('/pages/payresult/payresult', {
out_trade_no: order.out_trade_no
})
console.log('fail:' + JSON.stringify(err));
}
});
2、我的后端是TP6,我选的插件是Yansongdapay
我安装的是2版本,3版本我看作者还在更新,就没用,安装代码如下:
composer require yansongda/pay:~v2.10.2 -vvv
<?php
declare(strict_types=1);
namespace app\websit\controller;
use think\facade\Cache;
use think\facade\View;
use think\facade\Session;
use think\facade\Log;
use app\websit\BaseController;
use think\exception\Handle;
use Yansongda\Pay\Pay;
use think\facade\Db;
use think\facade\Config;
class Wxpay extends BaseController
{
public function submitOrder()
{
if ($this->request->isPost()) {
//对应上面第一步先创建自己的订单存起来,具体逻辑自己写一下
} else {
vae_assign(202, "ERROR");
}
}
//这个方法就是微信支付会返回的所有参数就在这里返回,
public function index()
{
//防止跨域
header('Access-Control-Allow-Origin: *');
header('Access-Control-Max-Age: 1800');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE');
header('Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, Token');
if ($this->request->isPost()) {
//配置文件最好单独配置出去,我这里放进来是为了方便演示查看
$config = [
'appid' => 'wxb3fxxxxxxxxxxx', // APP APPID
'app_id' => 'wxb3fxxxxxxxxxxx', // 公众号 APPID
'miniapp_id' => 'wxb3fxxxxxxxxxxx', // 小程序 APPID
'mch_id' => '145776xxxx',
'key' => 'mF2suE9sU6Mk1CxxxxIxxxxx',
'notify_url' => 'http://yanda.net.cn',
'cert_client' => './cert/apiclient_cert.pem', // optional, 退款,红包等情况时需要用到
'cert_key' => './cert/apiclient_key.pem',// optional, 退款,红包等情况时需要用到
'log' => [ // optional
'file' => './logs/wechat.log',
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
'mode' => 'normal',//这个参数有点重要
];
$params = $this->param;
// $total = floatval($amount);
// print_r($config);
$order = [
'out_trade_no' => $params['out_trade_no'],
'body' => $params['good_name'],
'total_fee' => $params['total_fee'] * 100, //
];
$wechat = Pay::wechat($config)->app($order)->send();
// $res = $alipay->send();// laravel 框架中请直接 `return $alipay`
} else {
vae_assign(202, "ERROR");
}
}
}
3、代码写好以后就是微信那边的配置了
1、微信开放平台申请创建APP,并开通微信支付
(1)微信开放平台https://open.weixin.qq.com
(2)不知道怎么申请和开通的小伙伴去百度一下
(3)微信支付的APPID是这里申请的APPID
(4)应用签名必须要填写正确,不然找几天也找不到报错原因
下载签名生成工具
https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html
(5)安装到手机上,打开后输入app的报名就可以获取了,需要注意的是这个app要是正式打包的才能获取,这个值要填到第三步那里
(6)微信支付操作证书获取可按这个操作流程进行:
https://www.sohu.com/a/234912109_100142931
证书下载下来要存到代码目录里面去,在支付配置的这里要用到
按以上操作流程做完,基本上可以成功唤起微信支付了,如果不行的话记得换一个手机尝试,很有可能会成功。
APP微信支付总结
大部分不成功的原因都是配置不正确,一定要多次检查配置参数,一个是自己的配置文件,另一个是微信开放平台以及微信支付官网的各种配置,错一个都要查几天,所以仔细核查是最同意解决问题的办法。
二、H5微信支付
(1)普通h5支付
要能正常唤起微信支付才算成功
1、第一步:微信支付官网,进行配置合法域名
2、前端公用上面的生成自己的订单代码,自己的也就是保存到自己数据库的订单,而支付的时候需要把这个订单号给微信那边就可以了,我这里直接调用支付接口,默认已经生成好了订单信息。
调用后端接口代码如下:
console.log('微信支付')
_that.$u.api.wxPayh5({
out_trade_no: order.out_trade_no,
good_name: order.good_name,
total_fee: order.total_fee,
}).then(res => {
console.log(res)
let redirect_url = window.location.href;
// let redirect_url = url+'&checkpay=true';
// console.log(res.data.replace(/\n/g,"")+'&redirect_url='+encodeURI(redirect_url));
//标记用户是否点击过微信支付,不管支付成不成功
uni.setStorage({
key: 'checkpay',
data: true,
success: function() {
//去掉返回值中的换行符号再跳转
window.location.href = res.data.replace(/\n/g, "") + '&redirect_url=' +
encodeURI(redirect_url)
}
})
console.log(order)
}).catch(err => {
console.log(err)
})
注意:微信h5支付需要后端返回一个跳转链接,而微信h5支付是没法通过这个链接获得用户支付结果的,需要主动去查询,就是这里跳转了之后就管他的了,支付状态需要再次请求,还应注意redirect_url
这个参数,是支付后返回的地址,需要和JSPAPI的域名属于同一个域名才行。
请仔细阅读这篇文档:https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/develop/chapter2_26.shtml
后端接口代码:使用的依然是Yansongda Pay
public function wxpayh5()
{
header('Access-Control-Allow-Origin: *');
header('Access-Control-Max-Age: 1800');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE');
header('Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, Token');
$config = Config::get('wechat');
$params = $this->param;
$order = [
'out_trade_no' => $params['out_trade_no'],
'body' => $params['good_name'],
'total_fee' => $params['total_fee'] * 100, //
];
return Pay::wechat($config)->wap($order)->send();// laravel 框架中请直接 `return $alipay`
}
3、如果上面的步骤都不出错,我们能唤起微信支付并返回到支付页面,这时候再去请求查看是否支付成功。
前端请求代码:
//这个接口需要后端判断支付接口并修改订单状态,
//有些人是在notify进行操作,我是直接查询结果,有了就改订单状态省事儿
_that.$u.api.wxpayh5queryorder({
out_trade_no: _that.order.out_trade_no,
buyType: _that.order.good_type,
user_id: _that.order.user_id,
price: _that.order.total_fee,
good_id: _that.order.good_id,
}).then(res => {
console.log(res);
uni.removeStorage({
key: 'checkpay',
success: () => {
//去结果页就好了
_that.$u.route('/pages/payresult/payresult', {
out_trade_no: _that.order.out_trade_no
})
}
})
}).catch(err => {
console.log(err);
})
后端代码:
public function wxpayh5queryorder()
{
$config = Config::get('wechat');
$params = $this->param;
$order = [
'out_trade_no' => $params['out_trade_no'],
];
// $order = '1514027114';
$result = Pay::wechat($config)->find($order);
if($result->trade_state =='SUCCESS'){
/* if ($params['buyType'] == 'bj') {
vae_stuopenbj($params);
}*/
//修改订单状态
if (!empty(Db::name('order')->where(['user_id' => $params['user_id'], 'out_trade_no' => $params['out_trade_no']])->update(['status' => 1]))) {
vae_assign(200, "OK");
}
// vae_assign(200, '支付成功');
}
vae_assign(200, '支付失败',[$result]);
}
普通h5微信支付总结
走到这里流程是基本走完了,不出意外就成功了,大部分人会卡在唤起微信支付的过程,看微信支付怎么提示的。
1、手机浏览器进行调试。
2、需要部署到正式环境进行调试。
3、需要确认JSPAPI配置是否正确。
微信普通h5支付还是挺简单的,比起支付宝的话,支付宝h5支付之后文章会更新。
(2)微信内置浏览器h5支付
微信内置浏览器支付与普通h5支付的区别
1、微信内置浏览器支付需要使用公众号支付而不是普通的JSAPI支付。
2、支付的时候后端需要用到openid。
获取openid需要由前端获取code然后后端提供接口换取openid,几年前我做小程序的时候跟后端扯半天搞不懂openid的来源,说白了就是前端先用code调用后端接口(接口由后端提供)换取openid,用户openid唯一,可直接持久化,然后支付的时候再把openid给后端,前端只需要提供code就行,下面会讲前端怎么获取code。
3、微信内置浏览器提供了唤起微信支付的方法,提供参数即可,不用像普通h5那样跳转。
4、微信公众号域名授权。
微信网页授权的的步骤:
进入微信公众平台——公众号设置——功能设置中找到“网页授权域名”,在这里填写我们部署的项目的域名。
在填写域名之前我们可以看到有一个txt文件,我们需要先把这个文件放置在项目部署的域名根目录下,记住是根目录。然后填写我们项目部署的服务器的域名,这里的域名记住不要加http或者https,而且微信公众号的网页授权域名必须是80或者443端口,一定要仔细看文档,填写的时候看说明。
获取openid前端部分
//进入页面直接询问一下有没有code
//没有就去请求
onLoad(options){
let code = _that.getQueryVariable('code');
if (!code) {
//请求参数:redirect_uri = https://xx.xx.xx/pages/checkout/checkout/
//appid:wx111111111111(公众号的appid)
//scope=snsapi_base 只要openid 不要其他信息,如果要其他信息要复杂一些
window.location.href =
'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx111111111111&redirect_uri=这里填你需要把code返回的地址&response_type=code&scope=snsapi_base&state=123#wechat_redirect';
}
_that.code = code
_that.getopenid(code);
},
methods:{
getopenid(code) {
let _that = this;
//这就是所说的用code换openid
_that.$u.api.getOpenId({
user_id: _that.userId,
code: code
}).then(res => {
uni.setStorage({
key:'uerInfo',
data:res,
success() {
window.reload();
}
})
}).catch(err => {
console.log(err)
})
},
}
获取openid后端代码
public function getOpenId()
{
if ($this->request->isPost()) {
$params = $this->param;
//参数1:appid-公众号的appid
//参数2:secret 公众号的secret
//不知道怎么查看的自己百度一下
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=xxx&secret=xxx&code='.$params['code'].'&grant_type=authorization_code';
$result =json_decode(file_get_contents($url));
vae_assign(200, "成功",[$result]);
if(!empty($result->openid)){
//我这里直接保存下来了,之后就捕获去了
$user = Db::name('user')->where('id',$params['user_id'])->strict(false)->update(['openid'=>$result->openid]);
if(empty($user)){
vae_assign(202, "修改用户openid失败");
}
$user_success = Db::name('user')->find(['id' => $params['user_id']]);
vae_assign(200, "成功",$user_success);
}
vae_assign(202, "获取openid失败",[$result]);
} else {
vae_assign(202, "ERROR");
}
}
上面的步骤完成后就拿到了openid,接下来又是重复的步骤了
1、先生成自己的订单,这一步不可少,方式上面写两遍了,返回查看。
2、调用后端接口,返回支付时所需要的参数:
startPayJSAPI(order) {
let _that = this;
_that.$u.api.wxPayWap({
out_trade_no: order.out_trade_no,
good_name: order.good_name,
total_fee: order.total_fee,
openid: _that.openid,
}).then(res => {
//拿到后端返回的参数直接进行支付操作
//payment方法在下面查看
_that.payment(res[0], (res) => {
//支付成功直接去修改订单状态就好了,我是想省事
//editOrderStatus方法可自行根据业务逻辑进行添加就好了
_that.editOrderStatus(order);
}, (err) => {
console.log(err);
})
}).catch(err => {
console.log(err)
})
},
3、后端返回微信公众号支付需要的参数:我同样使用的是Yansongda Pay
public function wxPayWap()
{
if ($this->request->isPost()) {
$params = $this->param;
$config = Config::get('wechat');
$order = [
'out_trade_no' => $params['out_trade_no'],
'body' => $params['good_name'],
'total_fee' => '1',
//相比多了openid参数
'openid' => $params['openid'],
];
//直接返回前端需要的参数
$result = Pay::wechat($config)->mp($order);
vae_assign(200, "OK",[$result]);
} else {
vae_assign(202, "ERROR");
}
}
延续前端payment方法
methods:{
payment: function(data, callback_succ_func, callback_error_func) {
//不是微信内置浏览器就不要去支付了
if (!this.checkWechat()) {
return;
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', this.jsApiCall, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', this.jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', this.jsApiCall);
}
} else {
this.jsApiCall(data, callback_succ_func, callback_error_func);
}
},
jsApiCall(data, callback_succ_func, callback_error_func) {
//使用原生的,避免初始化appid问题
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId: data['appId'],
timeStamp: data['timeStamp'],
nonceStr: data['nonceStr'], // 支付签名随机串,不长于 32 位
package: data['package'], // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: data['signType'], // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data['paySign'], // 支付签名
},
function(res) {
var msg = res.err_msg ? res.err_msg : res.errMsg;
//WeixinJSBridge.log(msg);
switch (msg) {
case 'get_brand_wcpay_request:ok': //支付成功时
if (callback_succ_func) {
callback_succ_func(res);
}
break;
default: //支付失败时
WeixinJSBridge.log('支付失败!' + msg + ',请返回重试.');
if (callback_error_func) {
callback_error_func({
msg: msg
});
}
break;
}
})
},
},
checkWechat: function() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/micromessenger/i) == 'micromessenger') {
//this.isWechatJsapi = true
return true;
} else {
this.isWechatJsapi = false
return false;
}
},
微信内置浏览器支付总结
按流程操作,基本上都是可以支付成功的,不成功就是公众号的参数配置错误,请多次进行检查,细心再细心!!!
1、微信内置浏览器进行调试。
2、需要部署到正式环境进行调试。
3、需要确认微信公众号配置是否正确。
4、微信公众号支付还需配置域名授权。
总结
本次一共完成三个微信支付实例,开发过程中遇到问题多数为阅读文档不认真导致的,支付请优先阅读官方文档
如果需要PC端支付教程的话,可以留言告诉我,我有精力了会更新这篇文章。