asp.net 微信jsapi支付

来源:互联网 发布:数据爆炸时代 编辑:程序博客网 时间:2024/05/21 09:48
开始做jsapi支付时看了好多的demo及好多的博客感觉有大坑,果不其然,一点一点从坑中爬出。
  1. 前期准备,首先微信公众号中的配置,现在微信支付中配置好支付授权目录,先解释一下支付授权目录时做什么的,在微信发起支付时要获取用户的openid,而获取openid之前要获取一个code,而这个code是获取openid的凭证,而在获取code时微信会有一个回调页面而这个页面就是你的授权支付目录,如果这个目录不正确则后续没有办法进行。例如:你要支付的页面为www.weixin.com/wxpay/JsApiPayPage.aspx时,你需要将目录配置为www.weixin.com/wxpay/以免出现问题。 支付授权目录
  2. 其次要配置的就是网页授权获取用户基本信息接口 网页授权获取用户基本信息 这个配置的作用使你能访问到支付的接口及回调页面能够返回,其中的域名必须是备案的。
  3. 正式开始从坑中爬,首先介绍微信调试工具微信web开发工具调微信页面神器,微信网站都可以用这个工具。首先拿到微信支付demo然后各种运行然后不行,首先在default页面中的<a href="http://paysdk.weixin.qq.com/example/ProductPage.aspx">JSAPI支付</a>全部都是微信的链接而不是你project的目录,这里在example目录中发现了所有的目录,你可以将default页面的中链接改为exampe目录中的页面,也可以不用改,直接运行example中你想要的接口的页面。下面看到jsapipage.aspx就是jsapi的demo了。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JsApiPayPage.aspx.cs" Inherits="WxPayAPI.JsApiPayPage" %><!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <meta http-equiv="content-type" content="text/html;charset=utf-8"/>    <meta name="viewport" content="width=device-width, initial-scale=1"/>     <title>微信支付样例-JSAPI支付</title></head>           <script type="text/javascript">               //调用微信JS api 支付               function jsApiCall()               {                   WeixinJSBridge.invoke(                   'getBrandWCPayRequest',                   <%=wxJsApiParam%>,//josn串                    function (res)                    {                        WeixinJSBridge.log(res.err_msg);                        alert(res.err_code + res.err_desc + res.err_msg);                     }                    );               }               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();                   }               }     </script><body>    <form runat="server">        <br/>        <div align="center">            <br/><br/><br/>            <asp:Button ID="submit" runat="server" Text="立即支付" OnClientClick="callpay()" style="width:210px; height:50px; border-radius: 15px;background-color:#00CD00; border:0px #FE6714 solid; cursor: pointer;  color:white;  font-size:16px;" />        </div>    </form></body></html>
using System;using System.Collections.Generic;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Net;using System.IO;using System.Threading;using LitJson;using System.Web.Security;namespace WxPayAPI{    public partial class JsApiPayPage : System.Web.UI.Page    {        public static string wxJsApiParam {get;set;} //H5调起JS API参数        protected void Page_Load(object sender, EventArgs e)        {            Log.Info(this.GetType().ToString(), "page load");            if (!IsPostBack)            {                string openid = Request.QueryString["openid"];                string total_fee = Request.QueryString["total_fee"];                //检测是否给当前页面传递了相关参数                if (string.IsNullOrEmpty(openid) || string.IsNullOrEmpty(total_fee))                {                    Response.Write("<span style='color:#FF0000;font-size:20px'>" + "页面传参出错,请返回重试" + "</span>");                    Log.Error(this.GetType().ToString(), "This page have not get params, cannot be inited, exit...");                    submit.Visible = false;                    return;                }                //若传递了相关参数,则调统一下单接口,获得后续相关接口的入口参数                JsApiPay jsApiPay = new JsApiPay(this);                jsApiPay.openid = openid;                jsApiPay.total_fee = int.Parse(total_fee);                //JSAPI支付预处理                try                {                    WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult();                    wxJsApiParam = jsApiPay.GetJsApiParameters();//获取H5调起JS API参数                                        Log.Debug(this.GetType().ToString(), "wxJsApiParam : " + wxJsApiParam);                    //在页面上显示订单信息                    Response.Write("<span style='color:#00CD00;font-size:20px'>订单详情:</span><br/>");                    Response.Write("<span style='color:#00CD00;font-size:20px'>" + unifiedOrderResult.ToPrintStr() + "</span>");                }                catch(Exception ex)                {                    Response.Write("<span style='color:#FF0000;font-size:20px'>" + "下单失败,请返回重试" + "</span>");                    submit.Visible = false;                }            }        }    }}

在这第一个坑,可以看到首先是获取querystring中的openid和total_fee
这两个参数是一个是关注微信的唯一标识和订单的价格,然而首先在获取openid这就是个坑,要获取openid首先要获取到code,在获取到code之后才能获取到openid和access_token。我的做法是在pageLode中加这个。

try   {    //调用【网页授权获取用户信息】接口获取用户的openid和access_token    jsApiPay.GetOpenidAndAccessToken();    mOpenid = jsApiPay.openid;    mAccess_token = jsApiPay.access_token;   }catch (Exception ex)   {       Response.Write("<span style='color:#FF0000;font-size:20px'>" + ex.Message + "</span>");    }

其中GetOpenidAndAccessToken方法就有将获取code带码

/**        *         * 网页授权获取用户基本信息的全部过程        * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html        * 第一步:利用url跳转获取code        * 第二步:利用code去获取openid和access_token        *         */        public void GetOpenidAndAccessToken()        {            if (!string.IsNullOrEmpty(page.Request.QueryString["code"]))            {                //获取code码,以获取openid和access_token                string code = page.Request.QueryString["code"];                Log.Debug(this.GetType().ToString(), "Get code : " + code);                GetOpenidAndAccessTokenFromCode(code);            }            else            {                //构造网页授权获取code的URL                string host = page.Request.Url.Host;                string path = page.Request.Path;                string redirect_uri = HttpUtility.UrlEncode("http://www.weixin.com/wxpay.aspx");                WxPayData data = new WxPayData();                data.SetValue("appid", WxPayConfig.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                {                    //触发微信返回code码                             page.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常                }                catch (System.Threading.ThreadAbortException ex)                {                }            }        }

其中首先会判断是否获取到了code,如果没有就会执行获取code操作,其中的redirect_uri就是回掉地址,会在这个页面返回code继续执行获取openid和access_token的操作。而在之前pageload中加的那段代码就是在同一个页面两次执行GetOpenidAndAccessToken方法。
4.下面是一个巨坑,当你获取到openid之后还有个非常重要的pay_sign要获取之后还有一个回调地址,这个地址是你在成功支付后微信返回的回调通知。每发起一次支付操作都要获取一次pay_sign操作,而这个参数是发起调用jsapi操作的必须的参数。

function jsApiCall()               {                   WeixinJSBridge.invoke(                   'getBrandWCPayRequest',                   <%=wxJsApiParam%>,//josn串                    function (res)                    {                        WeixinJSBridge.log(res.err_msg);                        alert(res.err_code + res.err_desc + res.err_msg);                     }                    );               }

就是<%=wxJsApiParam%>,而<%=wxJsApiParam%>是由

名称 变量名 描述 公众号id appId 商户注册具有支付权限的公众号成功后即可获得 时间戳 timeStamp 当前的时间 随机字符串 nonceStr 随机字符串,不长于32位。推荐随机数生成算法 订单详情扩展字符串 package 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=* 签名方式 signType 签名算法,暂支持MD5 签名 paySign 签名,详见签名生成算法

在demo中lib文件夹中的WxpayApi.cs中的UnifiedOrder方法中获取这些参数,而其中的回调页面的地址是写在配置文件中的 public const string NOTIFY_URL = “http://paysdk.weixin.qq.com/example/ResultNotifyPage.aspx“;而这个配置文件并不是webcofig是在lib中的config.cs中商户号等一系列的配置也在其中。之后就可以发起支付了。
5.最后一坑,支付成功后的返回,在js中只有一个

function (res) {                        // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。                        switch (res.err_msg)                        {                            case "get_brand_wcpay_request:ok":                                alert("支付成功");                                break;                            case "get_brand_wcpay_request:cancel":                                alert("支付取消");                                //location.href = "JsApiPayPage.aspx?tepid=1";                                break;                            default:                                alert("支付失败");                                //location.href = "JsApiPayPage.aspx?tepid=2";                                break;                        }                    }

真正的支付回调页面在ResultNotifyPage.aspx中,其中有回调支付的判断,更有返回的订单的信息,可以在这个页面对支付成功或失败的订单进行处理。

总结:微信jaspi的坑总算爬出来了,其中发起支付到最后的支付成功总共调用了4次接口。更深表demo很坑。

1 0