asp.net 微信jsapi支付

开始做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%>是由

名称变量名描述
公众号idappId商户注册具有支付权限的公众号成功后即可获得
时间戳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很坑。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

miffy-life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值