1、前言

“小魏呀,这个微信支付还要多久?”,“快了快了老板,就等着最后一步了。。。”,“搞快点哈,就等着上线呢”,“.........”

因公司业务需要微信支付,以前没弄过花了几天时间写了一个微信v3的JSAPI支付,我滴个乖乖,差点今年小孩的奶粉就没了,还好弄出来了。在这里面各种踩坑,在这里记录一下,我开发的是微信公众号上面拉起微信支付。后台是Core3.1的接口,前端用的是Vue。后面是部署在CentOS上面的

2、写代码之前的准备

你必须要有一个非个人性质的公众号(服务号),还有一个微信商户号。服务号申请地址微信商户号申请地址,具体的根据网站申请中按人家要求来就行了。个人建议把申请下来的公众号里面的appid 、appsecret,微信商户平台,商户号等数据保存在数据库中。

3、公众号、商户号配置

1)、公众号JS安全域名

登录公众号在左手边菜单:公众号设置---->功能设置------>JS安全域名----->设置。在里面可以连写5个域名下载文件上传到服务器上面 域名要经过ICP备案。可以访问到上面说的那个文件就可以了。

core3.1Api 发布后你放根目录是访问不到的,在configure里面加上访问静态文件 app.UseStaticFiles();然后在根目录建一个文件夹wwwroot 吧域名验证需要的txt文件丢进去  我是这么搞点。暂时没有想到其他骚操作

这里有人要问了 这个设置了是干嘛的,以前我也不知道是干嘛的哈哈,总有一颗好奇的心想知道。现在想想个人理解这个JS安全域名就是一个验证的机制吧。这里设置了加上微信服务号也有一个类似的,后面就可以调用JSAPI支付了。

2)、网页授权域名

这个紧接着在JS安全域名后面  跟着设置一下就可以了 我部署在CentOS上面 看一下文件夹目录,还有一个文件夹里面是是p12文件 后面会提到

这个网页授权意思就是后面要获取到用户的OpenId的时候 要通过这个域名授权。我们就能获取到用户的信息,授权登录这些配置。后面图上还有一个HHhhjZj的文件这个是商户号上面设置的。

3)、微信商户号设置

在微信商户平台上面选择产品中心---->开发配置,这里面设置支付目录。我这里是设置的一个 ,我也不是申请商户号的人 也没有这个权限 。上面的界面跟上面两步骤差不多就不啰嗦了。

4)、微信商户号的key,V3key设置

这里不再重复 参考微信开发文档  微信JSAPI开发接入前准备 https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_1.shtml 慢慢来哦,设置秘钥 我倒是自己想着(阿猫阿狗888666)AMAG66688这种来拼够32位就可以了哈哈。

4、Core3.1后端代码 详解

前面这些弄好了只算搭好了环境 下面开始撸码。微信支付的逻辑就是,获取用户的OpenId------->统一下单获取payId-------------->拉起微信支付------------>支付回调接口写逻辑

下面官网的

参考文档  JSAPI支付

1)、封装微信请求类

这里我单独封装了一个微信支付的请求类。因为调用v3支付必须要符合APIV3接口规则 ,具体的在微信官方文档看

using App.Common.Base;
using Microsoft.AspNetCore.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace App.Common.HttpHelper
{
/// <summary>
/// 请求类封装 别忘了 调用的时候添加 services.AddHttpClient() 调用都要加参数,实体类返回没有超时时间
/// 容器要添加
/// </summary>
public class HttpClientFactoryHelper
{
private readonly IHttpClientFactory _httpClientFactory;
private IWebHostEnvironment _webHostEnvironment;
public HttpClientFactoryHelper(IHttpClientFactory httpClientFactory, IWebHostEnvironment webHostEnvironment)
{
_httpClientFactory = httpClientFactory;
_webHostEnvironment = webHostEnvironment;
} public void SaveLog(string text)
{
string thisTime = DateTime.Now.ToString("yyyyMMdd");
var path = _webHostEnvironment.ContentRootPath + $"/ApiInterfaceErrorLog/";//绝对路径
string dirPath = Path.Combine(path, thisTime + "/");//绝对径路 储存文件路径的文件夹
if (!Directory.Exists(dirPath))//查看文件夹是否存在
Directory.CreateDirectory(dirPath);
string splitLine = "============================下一条==============================";
string timeNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
using StreamWriter file = new StreamWriter(dirPath + thisTime + ".txt", true);
file.WriteLine(timeNow+text);
file.WriteLine(splitLine);
}
#region //微信支付请求
/// <summary>
/// 微信请求Post
/// </summary>
/// <param name="url">地址</param>
/// <param name="requestString">参数</param>
/// <param name="privateKey">私有秘钥 p12文件</param>
/// <param name="merchantId">商户号</param>
/// <param name="serialNo">商户证书号</param>
/// <returns></returns>
public async Task<string> WeChatPostAsync(string url,string requestString, string privateKey, string merchantId, string serialNo)
{
try
{
var client = _httpClientFactory.CreateClient();
var requestContent = new StringContent(requestString);
requestContent.Headers.ContentType.MediaType = "application/json";
var auth = BuildAuthAsync(url, requestString, privateKey, merchantId, serialNo,"POST");
string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
client.DefaultRequestHeaders.Add("Authorization", value);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("User-Agent", "WOW64");
client.Timeout = TimeSpan.FromSeconds(60);
var response = await client.PostAsync(url, requestContent);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
else
{
return $"接口【{url}】请求错误,错误代码{response.StatusCode},错误原因{response.ReasonPhrase}具体的话========================================\n{JsonConvert.SerializeObject(response)}";
}
}
catch(Exception ex)
{
SaveLog($"接口【{DateTime.Now +url}】请求错误,错误代码{ex.Message}具体=============================================/n{ex.StackTrace}");
return ex.Message + ex.StackTrace;
}
}
/// <summary>
/// 微信请求
/// </summary>
/// <param name="url">地址</param>
/// <param name="requestString">参数</param>
/// <param name="privateKey">私有秘钥 p12文件</param>
/// <param name="merchantId">商户号</param>
/// <param name="serialNo">商户证书号</param>
/// <param name="method">Get或者Post</param>
/// <returns></returns>
public async Task<string> WeChatGetAsync(string url, string privateKey, string merchantId, string serialNo)
{
try
{
var client = _httpClientFactory.CreateClient();
var auth = BuildAuthAsync(url, "", privateKey, merchantId, serialNo,"GET");
string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
client.DefaultRequestHeaders.Add("Authorization", value);
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.Add("User-Agent", "WOW64");
client.Timeout = TimeSpan.FromSeconds(60);
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
else
{
return $"接口【{url}】请求错误,错误代码{response.StatusCode},错误原因{response.ReasonPhrase}";
}
}
catch (Exception ex)
{
SaveLog($"接口【{DateTime.Now + url}】请求错误,错误代码{ex.Message}具体=============================================/n{ex.StackTrace}");
return ex.Message+ ex.StackTrace;
}
}
protected string BuildAuthAsync(string url,string jsonParame ,string privateKey, string merchantId,string serialNo,string method="")
{
string body = jsonParame;
var uri = new Uri(url);
var urlPath = uri.PathAndQuery;
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = Path.GetRandomFileName(); string message = $"{method}\n{urlPath}\n{timestamp}\n{nonce}\n{body}\n";
//string signature = Sign(message, privateKey);
var path = _webHostEnvironment.WebRootPath + "/arsjkll/apiclient_cert.p12";
string signature = Sign(message,path, "1601849569");
return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
}
/// <summary>
/// 签名(CentOs 不支持 换了下面的)
/// </summary>
/// <param name="message">签名内容</param>
/// <param name="privateKey">秘钥</param>
/// <returns></returns>
public string Sign(string message,string privateKey)
{
byte[] keyData = Convert.FromBase64String(privateKey);
using CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob);
using RSACng rsa = new RSACng(cngKey);
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
/// <summary>
/// 获取签名证书私钥
/// </summary>
/// <param name="priKeyFile">证书文件路径</param>
/// <param name="keyPwd">密码</param>
/// <returns></returns>
private static RSA GetPrivateKey(string priKeyFile, string keyPwd)
{
var pc = new X509Certificate2(priKeyFile, keyPwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
return (RSA)pc.PrivateKey;
}
/// <summary>
//// <summary>
/// 根据证书签名数据 后面要做成配置在数据库中
/// </summary>
/// <param name="data">要签名的数据</param>
/// <param name="certPah">证书路径</param>
/// <param name="certPwd">密码</param>
/// <returns></returns>
public string Sign(string data, string certPah, string certPwd)
{
var rsa = GetPrivateKey(certPah, certPwd); var rsaClear = new RSACryptoServiceProvider(); var paras = rsa.ExportParameters(true);
rsaClear.ImportParameters(paras); var signData = rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signData);
}
#endregion }
public class CustomerHttpException : Exception
{
public CustomerHttpException() : base()
{ }
public CustomerHttpException(string message) : base(message)
{
}
}
public class ReturnData
{
/// <summary>
/// 返回码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 返回数据
/// </summary>
public object Data { get; set; }
/// <summary>
/// 成功默认
/// </summary>
/// <param name="data"></param>
/// <param name="msg"></param>
public static ReturnData ToSuccess(object data, string msg = "sussess")
{
var result = new ReturnData
{
Code = (int)HttpStatusCode.OK,
IsSuccess = true,
Msg = msg,
Data = data
};
return result; }
public static ReturnData ToFail(string msg)
{
var result = new ReturnData
{
Code = (int)HttpStatusCode.BadRequest,
IsSuccess = false,
Msg = msg
};
return result;
}
/// <summary>
/// 异常
/// </summary>
/// <param name="msg"></param>
/// <param name="data"></param>
public static ReturnData ToError(Exception ex, object data = null)
{
var result = new ReturnData
{
Code = (int)HttpStatusCode.InternalServerError,
IsSuccess = false,
Msg = "异常" + ex.Message,
Data = data
};
return result;
}
/// <summary>
/// 未经授权
/// </summary>
/// <param name="data"></param>
public static ReturnData ToNoToken(object data = null)
{
var result = new ReturnData
{
Code = (int)HttpStatusCode.Forbidden,
IsSuccess = false,
Msg = "未经授权不能访问",
Data = data
};
return result;
}
public static ReturnData Instance(object data, string msg, int code)
{
var result = new ReturnData
{
Code = code,
IsSuccess = false,
Msg = msg,
Data = data
};
return result; }
}
}

Sign签名官方给的只能在IIS上面运行 那是通过直接用私钥签名,我在CentOS上面不行

以前在IIS上面也是 但是这个只要配置IIS应用程序池,把夹子啊用户配置文件改成true就可以了。CentOS上面就不行了。后来我还是把p12文件放在了跟验证域名的那个位置,通过读取文件获取私钥。这个问题搞了我2天。。。不能跨平台。或者是我配置不对,后面有时间在研究。

2)、获取用户的OpenId

在用户统一下单的时候需要用户的OpenId就是这个用户在这个公众号下面的一个身份号码,关没关注获取了就不会变,所以我就是没调用统一下单之前就获取了保存在数据库中。统一下单的时候直接调用就可以了 参考连接  公众号网页授权

        private const string AuthorUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?";
private const string Oauth = "https://api.weixin.qq.com/sns/oauth2/access_token?";
private const string GetUserInfo = "https://api.weixin.qq.com/sns/userinfo?";
public string GetAuthorizeUrl(string appId, string redirectUrl, string state = "state", string scope = "snsapi_userinfo", string responseType = "code")
{
redirectUrl = HttpUtility.UrlEncode(redirectUrl, System.Text.Encoding.UTF8);
object[] args = new object[] { appId, redirectUrl, responseType, scope, state };
return string.Format(AuthorUrl + "appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect", args);
}
private string GetOpenIdUrl(string appId, string secret, string code, string grantType = "authorization_code")
{
object[] args = new object[] { appId, secret, code, grantType };
string requestUri = string.Format(Oauth + "appid={0}&secret={1}&code={2}&grant_type={3}", args);
return requestUri;
}
public GetOpenIdDto GetOpenid(string appId, string secret, string code, string grantType = "authorization_code")
{
string requestUri = GetOpenIdUrl(appId, secret, code, grantType);
var responseStr = _httpClientFactoryHelper.GetAsync(requestUri, null, 120).Result;
var obj = JsonConvert.DeserializeObject<GetOpenIdDto>(responseStr);
var getUserInfoUrl = GetUserInfo + $"access_token={obj.Access_Token}&openid={obj.OpenId}&lang=zh_CN";
var responseUser = _httpClientFactoryHelper.GetAsync(getUserInfoUrl, null, 120).Result;
SaveLog("OpenDetails", responseUser);
var objUser = JsonConvert.DeserializeObject<GetOpenIdDto>(responseUser); return objUser;
}

上面GetOpenId就是下面Api这里调用的

下面的接口地址就是/api/WeChatPay/SaveHospPatirntOpenId

 /// <summary>
/// 储存用户所在公众号下面的OpenId
/// </summary>
/// <param name="hospCode">医院|公众号编码</param>
/// <param name="userId">用户Id(登录的那个)</param>
/// <param name="code">微信服务器返回的code不用填</param>
/// <returns>跳转的returnUrl</returns>
[HttpGet]
public IActionResult SaveHospPatirntOpenId(string hospCode, int userId, string code = "")
{
var modelOpenId = _weChatPayService.IsSaveHospPatientOpenId(hospCode, userId);
var model = _weChatPayService.GetHospInfo(hospCode);
var modelNew = _weChatPayService.GetHospNewInfo(hospCode);
// var path = _configuration.GetValue<string>("ReturnUrl");
var returnUrl = $"http://打码/#/subSite?hospCode={model.HospCode}&hospId={modelNew.Id}";
//var returnUrl = HttpUtility.UrlEncode(returnUrltarget, System.Text.Encoding.UTF8);
if (modelOpenId != null)
return Redirect(returnUrl);
else
{ if (string.IsNullOrEmpty(code))
{
var redirectUrl = _weChatPayService.GetAuthorizeUrl(model.WxAppid, $"http://打码/WeChatPay/SaveHospPatirntOpenId?hospCode={hospCode}&userId={userId}");
return Redirect(redirectUrl);
}
else
{
//根据code和微信参数得到openid
var openIdModel = _weChatPayService.GetOpenid(model.WxAppid, model.WxAppsecret, code);
//业务处理保存到数据库
var modelOId=_weChatPayService.HospPatirntOpenIdSaveAsync(hospCode, userId, openIdModel).Result; return Redirect(returnUrl);
}
}
}

我这里的逻辑就是获取过了直接数据库获取没有获取过的微信授权获取。这里 如果用户没有授权实际上这个接口要访问2次的 第一次code没有值,第二次微信授权后通过redirect_uri带着code回来就获取到了用户的OpenId信息。

3)、统一下单

                    var path = RequestUrl.TRANSACTIONS;//https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
var timeOut = DateTime.Now.AddMinutes(10);
var address = $"{model.Address}/api/WeChatPay/NotifySuccess";//这个是微信支付状态返回发到你的接口上的地址
var reqDto = new
{
appid = model.WxAppid,
mchid = model.WxMchid,
description = req.Desc,
out_trade_no = troNo,
//time_expire = timeOut,
attach = regOrderModel.RegId.ToString(),
notify_url = address,
amount = new
{
total = req.Total,
currency = "CNY"
},
payer = new
{
openid = modelOpenId.OpenId
}
};
var reqJson = JsonConvert.SerializeObject(reqDto); var ret = _httpClientFactoryHelper.WeChatPostAsync(path, reqJson, model.PrivateKey, model.WxMchid, model.CardNo).Result;
var result = JsonConvert.DeserializeObject<JsApiResult>(ret);
if (!string.IsNullOrEmpty(result.Prepay_Id))
{
//时间戳
DateTimeOffset dto = new DateTimeOffset(DateTime.Now);
var unixTime = dto.ToUnixTimeSeconds().ToString();
//随机数
var nonMun = Guid.NewGuid().ToString("N").Substring(0, 30);
var pck = "prepay_id=" + result.Prepay_Id;
//签名
string message = $"{model.WxAppid}\n{unixTime}\n{nonMun}\n{pck}\n";
var pathfile = _webHostEnvironment.WebRootPath + "/arsjkll/apiclient_cert.p12";
string keyRsa = _httpClientFactoryHelper.Sign(message, pathfile, "1601849569");
//var keyRsa = _httpClientFactoryHelper.Sign(message, model.PrivateKey);
//构建JSAPI拉取支付的参数 匿名参数
var requestParam = new
{
appId = model.WxAppid,
timeStamp = unixTime,
nonceStr = nonMun,
package = pck,
signType = "RSA",
paySign = keyRsa
};
return Result.ToSuccess(requestParam);
}
else
{
return Result.ToFail("prepay_id获取失败+++++++" + ret);
}

上面统一下单获取到prepay_id在构造JSAPI拉取微信支付的参数返回到前端。签名上面有代码就不贴了。

4)、支付回调接口

 public Result NotifySuccess(NotifyDto ret)
{
SaveLog("NotifyParame", JsonConvert.SerializeObject(ret));
//ResourceASC
if (ret.Event_type == "TRANSACTION.SUCCESS")//支付成功
{ //解密数据报文
var dataJson = AesGcmHelper.AesGcmDecrypt(ret.Resource.Associated_data, ret.Resource.Nonce, ret.Resource.Ciphertext);
//转换对象接受
var data = JsonConvert.DeserializeObject<ResourceASC>(dataJson);
//获取当前订单记录实体
//自己的业务逻辑
}
else
{
SaveLog("NotifyFaile", JsonConvert.SerializeObject(ret));
}
return Result.ToSuccess("");
}
/// <summary>
/// 支付结果回调接收参数
/// </summary>
public class NotifyDto
{
/// <summary>
/// 通知ID通知的唯一ID
/// 示例值:EV-2018022511223320873
/// </summary>
public string Id { get; set; }
/// <summary>
/// 通知创建时间 通知创建的时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
/// 示例值:2015-05-20T13:29:35+08:00
/// </summary>
public string Create_time { get; set; }
/// <summary>
/// 通知类型 通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS
/// 示例值:TRANSACTION.SUCCESS
/// </summary>
public string Event_type { get; set; }
/// <summary>
/// 通知数据类型 通知的资源数据类型,支付成功通知为encrypt-resource
/// 示例值:encrypt-resource
/// </summary>
public string Resource_type { get; set; }
/// <summary>
/// 通知数据 通知资源数据
/// json格式,见示例
/// </summary>
public Resource Resource { get; set; }
/// <summary>
/// 回调摘要
/// 示例值:支付成功
/// </summary>
public string Summary { get; set; }
}

解密类

 public class AesGcmHelper
{
private static string ALGORITHM = "AES/GCM/NoPadding";
private static int TAG_LENGTH_BIT = 128;
private static int NONCE_LENGTH_BYTE = 12;
private static string AES_KEY = "v3秘钥"; public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
128,
Encoding.UTF8.GetBytes(nonce),
Encoding.UTF8.GetBytes(associatedData));
gcmBlockCipher.Init(false, aeadParameters); byte[] data = Convert.FromBase64String(ciphertext);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
}

支付返回的我保存了日志分享出来看看

之前一直没有调通,花了一天时间 找到了原因 统一下单的时候 里面不是谣传一个参数  支付金钱 total  我携程decmial类型了赋值 ,注意这里一定要int  单位是分数。支付提示 (系统繁忙、请稍后再试),一般这个错误就是参数不对,类型一定要跟官网对应起来

5)、Vue前端调用拉起支付

<template>
<div>
<van-nav-bar
left-text="返回"
left-arrow
@click-left="clickLeft"
title="支付订单"
/> <div class="figure">
<div>支付金额</div>
<div class="money">
¥ <span>{{ total }}</span>
</div>
<div style="font-size: 14px">
请在
<van-count-down
:time="countDownTime"
format="mm分ss秒"
style="display: inline"
@finish="countDownFinish"
/>
内支付完成,超时后订单自动取消
</div>
</div> <van-radio-group v-model="radio">
<van-cell-group>
<van-cell v-for="el in payType" @click="chkCheck(el)">
<template #right-icon>
<svg class="icon" aria-hidden="true">
<use :xlink:href="el.icon"></use>
</svg>
<span style="width: 80px; margin-left: 15px">{{ el.title }}</span>
<van-radio style="margin-left: 60%" :name="el.name" />
</template>
</van-cell>
</van-cell-group>
</van-radio-group> <div style="margin: 16px">
<van-button
round
block
type="info"
native-type="submit"
@click="onSubmit"
:disabled="!btnIsable"
>
{{ btnText }}
</van-button>
</div>
</div>
</template> <script>
export default {
data() {
return {
// cardNo: '',
// desc: '',
// hospCode: '',
// pointId: '',//号点Id
total: '',//支付费用
countDownTime: 5 * 60 * 1000,//支付剩余毫秒数
radio: '1',
appId: '',
timeStamp: '',
nonceStr: '',
package: '',
signType: '',
paySign: '',
btnText: '立即支付',
btnIsable: true,//支付按钮是否可用,true:可用 false:不可用
payType: [{
icon: '#icon-weixinzhifu',
title: '微信支付',
name: '1',
}],
}
},
methods: {
onSubmit() {
let vm = this;
let obj = {
"appId": vm.appId,//公众号名称
"timeStamp": vm.timeStamp,//时间戳,自1970年以来的秒数
"nonceStr": vm.nonceStr,//随机串
"package": vm.package,
"signType": vm.signType,
"paySign": vm.paySign //签名
}; function onBridgeReady() {
WeixinJSBridge.invoke('getBrandWCPayRequest', obj,
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
vm.btnIsable = false;
vm.closePage('支付成功');//后期跳转到挂号记录页面
}
});
}
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 {
onBridgeReady();
}
},
chkCheck: (el) => {
return el.name;
},
countDownFinish() {
//倒计时结束销号,不提交支付
this.btnIsable = false;
this.closePage('支付超时');
},
clickLeft() {
this.$dialog.confirm({
title: '提示',
message: '支付尚未完成,是否继续支付',
})
.then(() => {
// on confirm
})
.catch(() => {
this.$router.go(-1);
});
},
getBaseData() {
// 获得支付信息
let vm = this;
let p = vm.$route.params;
if (JSON.stringify(p) != "{}") {
this.appId = p.appId;
this.total = p.fee;
this.nonceStr = p.nonceStr;
this.package = p.package;
this.paySign = p.paySign;
this.countDownTime = p.paymentDeadline - vm.$moment().valueOf();
this.signType = p.signType;
this.timeStamp = p.timeStamp;
} else {
this.closePage('无效请求');
}
},
closePage(text, num = 5, route = 'home') {
this.btnIsable = false;
let lock = setInterval(() => {
num--;
this.btnText = `${text},${num}秒后关闭`;
if (num == 0) {
clearInterval(lock);
this.$router.push({ path: route });
}
}, 1000);
},
},
mounted() {
this.getBaseData();
}
}
</script> <style>
.figure {
background: #fff;
text-align: center;
margin: 10px auto;
padding: 10px 0;
color: gray;
}
.money {
color: orange;
font-size: 16px;
margin: 15px auto;
}
.money span {
font-size: 36px;
}
</style>

5、总结

纸上得来终觉浅,看着微信官网的,v3支付只有 爪哇 跟 派森 的sdk 。NET的还是自己来。里面的各种术语花里花哨的感觉 哈哈。可能是现在的我心里太多的浮躁了,还是要慢慢静下心来看。本文出处魏杨杨博客园

原文链接我自己贴上https://www.cnblogs.com/w5942066/p/14313946.html

做个内心阳光的人。不忧伤,不心急。坚强、向上,靠近阳光,成为更好的自己,你不需要别人过多的称赞,因为你自己知道自己有多好。内心的强大,永远胜过外表的浮华。

Core3.1 微信v3 JSAPI支付的更多相关文章

  1. Core3.1 微信v3 JSAPI支付 退款

    1.前言 上一篇写了<Core3.1 微信v3 JSAPI支付>,这个属于v3的接口规则,现在研究了下退款的接口我写的时候它属于v2接口规则文档.但凡微信支付文档里面写清楚点我也不会在这里 ...

  2. 微信v3 JSAPI最新接口错误 get_brand_wcpay_request:fail

    WxPay.JsApiPay.php文件下 原始接口代码 /** * * 获取jsapi支付的参数 * @param array $UnifiedOrderResult 统一支付接口返回的数据 * @ ...

  3. 微信JSApi支付~集成到MVC环境后的最后一个坑(网上没有这种解决方案)

    返回目录 大叔第一人 之前写了关于微信的坑<微信JSApi支付~坑和如何填坑>,今天将微信的jsapi支付封装到了MVC环境里,当然也出现了一些新的坑,如支付参数应该是Json对象而不是J ...

  4. 微信JSAPI支付

    最近在微信H5页面内集成微信JSAPI支付,遇到不少问题,现将集成步骤及遇到的问题记录如下: 1.官方下载SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api ...

  5. 微信JSApi支付~订单号和微信交易号

    返回目录 谈谈transactionId和out_trade_no 前一篇微信JSApi支付~坑和如何填坑文章反映不错,所以又写了个后篇,呵呵. 每个第三方在线支付系统中都会有至少两类订单号,其一为支 ...

  6. 微信JSApi支付~坑和如何填坑

    返回目录 微信一直用着不爽,这几天研究它的jsapi支付,即在微信内打开H5页面,完成支付的过程,在这个过程中,你将会遇到各种各样的问题,而大叔将把这些问题的解决方法写一下,希望可以给你带来帮助! 一 ...

  7. asp.net微信jsapi支付

    1.前台页面: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"><head ru ...

  8. 微信支付系列(2)——jsapi支付源码解析

    版权声明:转载请注明出处:http://blog.csdn.net/m0sh1 http://www.share345.com 在微信支付 开发者文档页面 下载最新的 PHP SDK http://m ...

  9. 微信JSAPI支付(比较详细) 关于getRrandWCPayRequest:fail_invalid appid 错误

    原文:微信JSAPI支付(比较详细) 关于getRrandWCPayRequest:fail_invalid appid 错误 首先微信支付需注册  微信公从平台开发 和 微信支付商户平台 关于4个密 ...

随机推荐

  1. Loading class `com.mysql.jdbc.Driver'. This is deprecated警告处理

    com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别 mysql客户端6以后,数据库驱动com.mysql.jdbc.Driver'已经被弃用了.应当 ...

  2. 机器学习速查表(cheatsheet)资源汇总分享

    本文收集整理了机器学习相关速查表(Machine Learning Cheatsheet),包含机器学习.Python.Numpy.Pandas.Matplotlib.线性代数.微积分.统计学.概率论 ...

  3. DVWA-文件包含-目录遍历学习笔记

    参考文献资料: https://www.cnblogs.com/s0ky1xd/p/5823685.html https://www.cnblogs.com/yuzly/p/10799486.html ...

  4. asp.net mvc ajax文件上传

    前台页面提交文件 <!DOCTYPE html> <html> <head> <meta name="viewport" content= ...

  5. mysqld程序结构介绍

    说明:mysqld程序结构模型就是------> SQL语句的执行过程· 分为三大部分:连接层,SQL层,存储引擎层 #1.连接层功能 (1).TCP/IP或者Socket的连接方式    (2 ...

  6. Autofac官方文档翻译--二、解析服务--2隐式关系类型

    Autofac 隐式关系类型 Autofac 支持自动解析特定类型,隐式支持组件与服务间的特殊关系.要充分利用这些关系,只需正常注册你的组件,但是在使用服务的组件或调用Resolve()进行类型解析时 ...

  7. Telegraf+Influxdb+Grafana自动化运维监控

    概述:Telegraf收集信息,influxdb时序数据库存储数据,grafana平台展示数据,并进行监控告警,组成一个自动化运维监控平台. 一.influxdb ​ InfluxDB是一个由Infl ...

  8. 深入浅出 Git

    开篇 你可能遇到过 如果你遇到这个场景,那你可能需要版本控制. 什么是版本控制 版本控制最主要的功能就是追踪文件的变更.它将什么时候.什么人更改了文件的什么内容等信息忠实地了已录下来.每一次文件的改变 ...

  9. 高并发redis分布式锁

    1.方法一 2方法二

  10. C语言输入字符串

    首先强调一点,C语言没有字符串的概念!所谓的字符串实际上还是以数组形式保存的. 方法1  -- 通过"%s"输入 优点:简单明了,输入字符只要不大于数组长度都可以. #includ ...