微信支付有多种方式,本文章主要介绍JsApi支付,前端调用使用的是vue,后端使用的是c# webapi,后端使用了插件Senparc.Weixin.TenPayV3。
开发工具:
前端:hbuilder
后端:Visual Studio 2022
注意:
小程序和公众号区别:
1、后端配置global.json的时候,Appid用对应平台上申请的
2、后端代码没有什么区别
3、vue在生成预付订单后,调起手机支付输入密码页面有区别,由于开发工具用的是Hbuilder,小程序支付可以直接用官方的wx.requestPayment,公众号不支持这种写法,所以稍微有一点点区别,公众号直接用微信公众号官方方法就可以了,下文中有贴出代码。
微信商户平台配置
在微信商户平台开通JsApi接口
支付授权目录设置,注意路径要到你api的实际路径,不要只写到域名
API安全设置(后端配置需要TenPayV3_Key、TenPayV3_PrivateKey、TenPayV3_SerialNumber,都是在此页面设置的)
后端配置
我后端开发用的是Visual Studio 2022,要安装插件Senparc.Weixin.TenPayV3(盛派开发的)
配置global.json
//Senparc.Weixin SDK 设置"SenparcWeixinSetting":{//以下为 Senparc.Weixin 的 SenparcWeixinSetting 微信配置//微信全局"IsDebug":true,//微信支付V3(新版)"TenPayV3_AppId":"xxxxxxxxx",// "TenPayV3_AppSecret":"xxxxxxxxx","TenPayV3_MchId":"xxxxxx",//商户号"TenPayV3_TenpayNotify":"http://cd.xxxxxxxxx.com/PayNotifyUrl",//支付成功后的回调"TenPayV3_PrivateKey":"xxxx....",//(新)证书私钥(在证书文件夹中,很长一串,自己去复制)"TenPayV3_SerialNumber":"xxxx...",//证书序列号(在商户平台申请证后,复制过来)"TenPayV3_ApiV3Key":"xxxxxxxxx",//(新)APIv3 密钥 跟上面的TenPayV3_Key填同一个},
在program.cs要注册Senparc,代码如下
先添加引用
usingSenparc.Weixin.AspNet;usingSenparc.Weixin.AspNet.RegisterServices;usingSenparc.Weixin.Entities;usingSenparc.Weixin.RegisterServices;usingSenparc.Weixin.TenPayV3;
继续在program.cs中添加注册代码
//Senparc.Weixin 注册(必须)
builder.Services.AddSenparcWeixinServices(builder.Configuration);var app = builder.Build();var senparcWeixinSetting = app.Services.GetService<IOptions<SenparcWeixinSetting>>()!.Value;//启用微信配置(必须)var registerService = app.UseSenparcWeixin(app.Environment,null/* 不为 null 则覆盖 appsettings 中的 SenpacSetting 配置*/,null/* 不为 null 则覆盖 appsettings 中的 SenpacWeixinSetting 配置*/,
register =>{},(register, weixinSetting)=>{//注册公众号信息(可以执行多次,注册多个小程序)
register.RegisterTenpayApiV3(weixinSetting,"【xxx项目名称】微信支付(ApiV3)");//自定义一个名字});
支付流程
1、前端vue调用后端api,生成一条状态为待支付的数据
2、待支付订单生成结果返回到前端,前端发起支付,跳转输入密码界面
3、输入密码成功付款后,自动触发后端支付成功回调函数,修改支付状态
vue(公众号)
```html
//生成订单预支付信息
Recharge() {
let that = this
var recharge = {
virtual_card_number: '123',
phone: this.memberinfo.phone,
recharge_money: this.renew_money,
recharge_type: this.renew_type,
openid: uni.getStorageSync('open_id')
}//传输到后端api的参数,根据自己项目修改
get_prepay_id(recharge).then(res => {
this.prepay_result = res.data.data
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
this.onBridgeReady();
}
})
},
onBridgeReady() {
let that=this
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":that.prepay_result.appId , //公众号ID,由商户传入
"timeStamp":that.prepay_result.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": that.prepay_result.nonceStr, //随机串
"package": that.prepay_result.package,
"signType": that.prepay_result.signType, //微信签名方式:
"paySign": that.prepay_result.paySign//微信签名
},
function(res){
console.log('this.prepay_result',that.prepay_result)
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用者支付成功
alert('支付成功');
} else if(res.err_msg == "get_brand_wcpay_request:fail" ){
// 使用者支付失败
alert('支付失败');
}
}
);
}```
**
vue(小程序)
Recharge() {
let that = this
var recharge = {
virtual_card_number: '123',
phone: this.memberinfo.phone,
recharge_money: this.renew_money,
recharge_type: this.renew_type,
openid: uni.getStorageSync('open_id')
}//传输到后端api的参数,根据自己项目修改
get_prepay_id(recharge).then(res => {
var result = res.data.data
wx.requestPayment({
timeStamp: result.timeStamp,
nonceStr: result.nonceStr,
package: result.package,
signType: result.signType,
paySign: result.paySign,
success(res) {
console.log('支付成功', res)
},
fail(res) {
console.log('支付失败', res)
}
})
})
},
**后端 WebApi
生成预支付订单
/// <summary>/// JsApi支付/// </summary>/// <param name="record">订单信息</param>/// <returns></returns>//发布到服务器iis时,选择应用池-鼠标右键–>高级设置–>进程模型–>加载用户配置文件–>设置为truepublicasyncTask<ApiReturnValue>GetPrepayid(c_recharge_record record){ApiReturnValue<wx_pay_param> apiresult =newApiReturnValue<wx_pay_param>();try{string HostIp ="xxxx.xx.xx.xxx";//生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一record.sp_billno ="cz_"+SystemTime.Now.ToString("yyyyMMddHHmmss");record.recharge_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");var body ="智慧停车充值";int price =record.recharge_money*100;//单位:分//int price =1;//单位:分var basePayApis =newSenparc.Weixin.TenPayV3.Apis.BasePayApis(Config.SenparcWeixinSetting);var requestData =newSenparc.Weixin.TenPayV3.Apis.BasePay.TransactionsRequestData(Config.SenparcWeixinSetting.TenPayV3_AppId, Config.SenparcWeixinSetting.TenPayV3_MchId, body,record.sp_billno,newSenparc.Weixin.TenPayV3.Entities.TenpayDateTime(SystemTime.Now.AddMinutes(120).DateTime,false), HostIp, Config.SenparcWeixinSetting.TenPayV3_TenpayNotify,null,new(){ currency ="CNY", total = price },new(record.openid),null,null,null);var result =await basePayApis.JsApiAsync(requestData);if(result.ResultCode.Success ==true){var packageStr ="prepay_id="+ result.prepay_id;var jsApiUiPackage = TenPaySignHelper.GetJsApiUiPackage(Config.SenparcWeixinSetting.TenPayV3_AppId, result.prepay_id);wx_pay_param param =newwx_pay_param{
prepay_id = result.prepay_id,//预付_id
appId = Config.SenparcWeixinSetting.TenPayV3_AppId,//appId
timeStamp = jsApiUiPackage.Timestamp,//时间戳
nonceStr = jsApiUiPackage.NonceStr,//随机字符串,长度为32个字符以下
package = packageStr,// 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id = ***
signType ="RSA",// 签名算法,应与后台下单时的值一致
paySign = jsApiUiPackage.Signature//签名};//插入一条订单
DB.Insertable(record).ExecuteCommand();
apiresult.data = param;}else{
apiresult.code =500;
apiresult.message = result.ResultCode.ErrorCode.ToString()+ result.ResultCode.ErrorMessage + result.ResultCode.Solution;}}catch(Exception ex){
apiresult.code =500;
apiresult.message = ex.Message;}return apiresult;}
支付回调函数
//支付成功后的回调[HttpPost("PayNotifyUrl")]publicasyncTask<ApiReturnValue>PayNotifyUrl(){ApiReturnValue api_result =newApiReturnValue();try{//获取微信服务器异步发送的支付通知信息var resHandler =newTenPayNotifyHandler(HttpContext);var orderReturnJson =await resHandler.AesGcmDecryptGetObjectAsync<OrderReturnJson>();//记录日志
Senparc.Weixin.WeixinTrace.SendCustomLog("PayNotifyUrl 接收到消息", orderReturnJson.ToJson(true));//演示记录 transaction_id,实际开发中需要记录到数据库,以便退款和后续跟踪string out_trade_no = orderReturnJson.out_trade_no;//获取支付状态string trade_state = orderReturnJson.trade_state;//验证请求是否从微信发过来(安全)NotifyReturnData returnData =new();//验证可靠的支付状态if(orderReturnJson.VerifySignSuccess ==true&& trade_state =="SUCCESS"){
returnData.code ="SUCCESS";//正确的订单处理/* 提示:
* 1、直到这里,才能认为交易真正成功了,可以进行数据库操作,但是别忘了返回规定格式的消息!
* 2、上述判断已经具有比较高的安全性以外,还可以对访问 IP 进行判断进一步加强安全性。
* 3、下面演示的是发送支付成功的模板消息提示,非必须。
*/
recharge_service.recharge_callback(out_trade_no);//这个方法自定义,我这里是直接去改变订单的状态为已支付}else{
returnData.code ="FAILD";//错误的订单处理
returnData.message ="验证失败";//此处可以给用户发送支付失败提示等}#region 记录日志(也可以记录到数据库审计日志中)var logDir = ServerUtility.ContentRootMapPath(string.Format("~/App_Data/TenPayNotify/{0}", SystemTime.Now.ToString("yyyyMMdd")));if(!Directory.Exists(logDir)){
Directory.CreateDirectory(logDir);}var logPath = Path.Combine(logDir,string.Format("{0}-{1}-{2}.txt", SystemTime.Now.ToString("yyyyMMdd"), SystemTime.Now.ToString("HHmmss"), Guid.NewGuid().ToString("n").Substring(0,8)));using(var fileStream = System.IO.File.OpenWrite(logPath)){var notifyJson = orderReturnJson.ToString();await fileStream.WriteAsync(Encoding.Default.GetBytes(notifyJson),0, Encoding.Default.GetByteCount(notifyJson));
fileStream.Close();}#endregion}catch(Exception ex){
WeixinTrace.WeixinExceptionLog(newWeixinException(ex.Message, ex));throw;}return api_result;}
版权归原作者 一蓑烟雨*任平生 所有, 如有侵权,请联系我们删除。