微信JSAPI支付
微信公众号支付流程:首先调用【网页授权获取用户信息】接口获取用户的openid和access_token:
一、 获取code及openid
1.前台页面首先判断code是否存在,不存在则构造网页授权获取code的URL
mui.ready(function () {
//读取localStorage的用户信息
if (user != undefined) {
user = JSON.parse(user);
userid = user.UserId;
var vCode = getQueryString("code");
if (is_weixn()) {
orderid = getQueryString("oid");
amount = getQueryString("amount");
}
$("#h_amount").html(amount);
if (is_weixn()) {
mui.ajax({
url: '/Payment/WXPay/getWxInfo',
type: 'post',
data: {
code: vCode
},
dataType: 'JSON', //服务器返回json格式数据
//timeout: 5000, //超时时间设置为5秒;
success: function (json) {
var res = eval('(' + json + ')'); //获取json数据
openid = res.openid;
access_token = res.access_token;
},
error: function (xhr, type, errorThrown) {
console.log('错误');
//异常处理;
//mui.alert('网络延时,请重新加载!', '系统提示');
}
});
}
} else {
}
});
判断是否微信浏览器代码:
//判断是否微信内部浏览器
function is_weixn() {
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
return true;
} else {
return false;
}
}
------转到后台获取code
/// <summary>
/// 充值页面
/// </summary>
/// <returns></returns>
public ActionResult Recharge()
{
if (Session["openid"] == null)
{
try
{
//调用【网页授权获取用户信息】接口获取用户的openid和access_token
string redirurl = HttpUtility.UrlEncode("http://xxx.com/Payment/WXPay/Recharge");
jsp.GetOpenidAndAccessToken(redirurl);
}
catch (Exception ex)
{
//Response.Write(ex.ToString());
//throw;
}
}
return View();
}
网页授权用户的过程:
public void GetOpenidAndAccessToken(string redirecturi)
{
if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["code"]))
{
//获取code码,以获取openid和access_token
string code = HttpContext.Current.Request.QueryString["code"];
Log.Debug(this.GetType().ToString(), "Get code : " + code);
GetOpenidAndAccessTokenFromCode(code);
}
else
{
//构造网页授权获取code的URL
string redirect_uri = redirecturi;//HttpUtility.UrlEncode("http://share.chn-nbiot.com/Payment/WXPay/Recharge");
WxPayData data = new WxPayData();
data.SetValue("appid", WxPayConfig.JSAPI_APPID);
data.SetValue("redirect_uri", redirect_uri);
data.SetValue("response_type", "code");
data.SetValue("scope", "snsapi_base");
data.SetValue("state", "STATE" + "#wechat_redirect");
string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
try
{
HttpContext.Current.Session["url"] = url;
//触发微信返回code码
HttpContext.Current.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常
}
catch (System.Threading.ThreadAbortException ex)
{
}
}
}
解析:
1.首先支付页面会先调用【网页授权获取用户信息】接口获取用户的openid和access_token, 如果code没有获取到,则先构造网页授权获取code的URL。
2.HttpContext.Current.Response.Redirect(url); 就是重定向URL到微信端获取code码。获取到之后在返回到你的界面,取到code码之后,拿着code码获取openid和access_token。
二、统一下单获得签名数据
统一下单:
public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut = 6)
{
inputObj.SetValue("appid", WxPayConfig.JSAPI_APPID);//公众账号ID
inputObj.SetValue("mch_id", WxPayConfig.JSAPI_MCHID);//商户号
inputObj.SetValue("spbill_create_ip", WxPayConfig.IP);//终端ip
inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
//签名
inputObj.SetValue("sign", inputObj.MakeSign(WxPayConfig.JSAPI_KEY));
string xml = inputObj.ToXml();
var start = DateTime.Now;
string response = HttpService.Post(xml, url, false, timeOut);
var end = DateTime.Now;
int timeCost = (int)((end - start).TotalMilliseconds);
WxPayData result = new WxPayData();
result.FromXml(response);
return result;
}
签名的KEY要是商户对应的API秘钥,否则签名错误。
获得统一下单结果:
public WxPayData GetUnifiedOrderResult(string outno, decimal total_fee, string opid)
{
//统一下单
WxPayData data = new WxPayData();
data.SetValue("body", "余额充值");
data.SetValue("attach", "test");
data.SetValue("out_trade_no", outno);
data.SetValue("total_fee", decimal.ToInt32(total_fee * 100).ToString());
data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
data.SetValue("goods_tag", "test");
data.SetValue("trade_type", "JSAPI");
data.SetValue("openid", opid);
WxPayData result = WxPayApi.UnifiedOrder(data);
if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
{
Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
// throw new WxPayException("UnifiedOrder response error!");
}
unifiedOrderResult = result;
return result;
}
微信返回来的return_code和result_code都为SUCCESS的时候,才会正确返回数据,拿到我们想要的数据后,再进行一次签名
WxPayData newpay = new WxPayData();
newpay.SetValue("appId", WxPayConfig.JSAPI_APPID);
newpay.SetValue("timeStamp", WxPayData.GetTimeStamp());
newpay.SetValue("nonceStr", wpd.GetValue("nonce_str"));
newpay.SetValue("package", "prepay_id=" + wpd.GetValue("prepay_id"));
newpay.SetValue("signType", "MD5");
newpay.SetValue("paySign", newpay.MakeSign(WxPayConfig.JSAPI_KEY)); //再次生成签名
注意:时间戳是10位数字,package是固定写法prepay_id=微信返回来的prepay_id,签名方法signType是MD5。
组合一下对象返回到前台拉起微信支付:以下是我的对象名,可自行修改。
但appid、noncestr、timestamp、trade_type、package、signType、sign 是前台必须的字段,一个不能少!!
ReturnWxpay rwpay = new ReturnWxpay
{
appid = newpay.GetValue("appId").ToString(),
noncestr = newpay.GetValue("nonceStr").ToString(),
timestamp = newpay.GetValue("timeStamp").ToString(),
trade_type = wpd.GetValue("trade_type").ToString(),
package = newpay.GetValue("package").ToString(),
signType = newpay.GetValue("signType").ToString(),
sign = newpay.GetValue("paySign").ToString()
};
-----------回到前台调起支付,以下是固定写法。
注意注意::这里的前台字段的大小写,一定要对应,跟后台有差别,不要搞错了!!
function callpay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
} else {
jsApiCall();
}
}
//调用微信JS api 支付
function jsApiCall() {
WeixinJSBridge.invoke('getBrandWCPayRequest', {
"appId": paystr.appid, //公众号名称,由商户传入
"timeStamp": paystr.timestamp, //时间戳,自1970年以来的秒数
"nonceStr": paystr.noncestr, //随机串
"package": paystr.package,
"signType": paystr.signType, //微信签名方式:
"paySign": paystr.sign //微信签名
},
function (res) {
if (res.err_msg === "get_brand_wcpay_request:cancel") {
mui.alert('支付异常!', '提示');
return false;
} else if (res.err_msg === "get_brand_wcpay_request:ok") {
window.location.href = "../../../m/PersonalCenter/wallet.html";
mui.alert('支付成功!', '提示');
}
return true;
}
);
}
如果调起支付没问题,就会有支付界面出现啦。。支付成功后有个回调函数,如果支付成功后会返回re "get_brand_wcpay_request:ok",失败会返回"get_brand_wcpay_request:cancel",可自行处理条抓页面!!
最后附上获取code码的JS
//获取url的参数
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
阳光总在风雨后,相信有彩虹——MrLi