微信支付.NET版开发总结(JS API),好多坑,适当精简

前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下。接下来,按照开发步骤,细数一下,我遇到的那些坑。

【坑1】官方邮件中下载的demo只有PHP版本,其他版本没有给链接。可能让人误以为只有PHP版本,事实上,各种版本都有。

拿到了腾讯发给客户的,微信支付商户资料,邮件中提示:证书的详细使用方案,请查看微信支付开发接口文档。根据邮件微信支付开发接口文档的链接,定向到一个新的邮件附件,里面的内容:

  3. 使用公众号发起支付请求

  使用JS API在微信的网页中发起支付请求,详细方法见文档中有关JS API的章节。
  微信支付接口文档及demo(公众账号).zip点击下载

微信支付接口文档及demo(公众账号).zip,下载以后包含

  【微信支付】微信公众号支付接口文档V3.3.7

  公众账号支付DEMO,只有PHP版。

之前看到别人说,为什么现在很多微信公众平台项目都用PHP开发,因为腾讯官方的Demo很多只给了PHP版本,心里暗骂,怎么微信支付这么重要的东西也只给PHP版,哎,先把PHP版本跑通吧。于是在本地配置PHP环境,修改给的demo的配置参数。运行demo,看到请在微信客户端中打开链接的提示,于是把它部署到朋友服务器,在微信中去测试,结果,报一个json扩展方法不支持,于是去搜索,怎么配置这个扩展方法。到晚上12点了,睡觉了,没搞好。临睡前想的是,PHP版本就算支付走通了,更新订单状态的代码也不好搞呀,逻辑比较复杂,用PHP再写一遍很烦人,我PHP基本不会。

这里走弯路了,其实是有.net版本的demo的,无意间在公众平台的后台点击链接看到了商户平台开发者文档,大喜过望,SDK下载->Demo下载,JAVA,.NET C#,PHP,IOS,Android都有。幸福的下载.NET版

.NET版本Demo第一处修改:default.aspx页面里面的链接路径,居然都指向到paysdk.weixin.qq.com,改成自己的路径后,还是运行报错,因为下面的坑:

【坑2】代理服务器设置,注释就可以了,lib\HttpService.cs中get和post方法里。

         //下面设置HttpWebRequest的相关属性
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "POST";
                request.Timeout = timeout * 1000+60000;//默认传过来是6秒,手动加了一分钟

                //设置代理服务器
                //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                //proxy.Address = new Uri(WxPayConfig.PROXY_URL);              //网关服务器端口:端口
                //request.Proxy = proxy;

【坑3】redirect_url参数错误,网页授权->网页账号,填写域名。

因为我选择的的“JS API”支付,这种支付需要网页授权,先获取code,再拿code去获取openid和prepay_id。这个网页授权需要登录微信公众平台。点击左侧菜单“开发者中心”,在右侧“权限列表”中找到“网页账号”,点击最右侧的修改,把测试的域名写进去,注意不要加http。经过测试发现,域名必须完全匹配,设置顶级域名domain.com,程序是pay.domain.com的二级域名都不行。

微信公众平台登陆还要微信管理员在个人微信号上授权,要等客户公司员工上班了,才授权,增加了解决问题等待的时间。

【坑4】 数据类型要和接口文档要求的完全一致。报错:ERROR 下单失败,WxPayData字段数据类型错误

项目中的订单编号是long类型,微信接口规范是string类型,报了上面的错误,改为string类型就好了。这个属于需要注意的,严格来说,不能算坑

趟过上面的几个坑,终于支付成功了。接下来,要去完成更新订单的逻辑。

ResultNotify页面更新订单的逻辑并没有按照预料的走,查看IIS的日志,微信有发请求到ResultNotify页面,状态是500内部服务器错误。网站程序的Log中并没有记录到,一步一步用Log.Debug,记录程序走的情况,发现微信订单号应该成功获取到了,并且验证签名成功,返回的XML也正常。

INFO WxPayAPI.ResultNotify: Check sign success

DEBUG WxPayApi: OrderQuery response : <xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<total_fee>10</total_fee>
...

于是,在关键代码处,添加了try catch,这一步早就应该做,就不用一步一步的试错了,走弯路了,异步通知页面的找出错误很麻烦,要支付一次,看响应的结果。接下来,有依次经历了以下几个异常。

【坑5】ERROR WxPayAPI.ResultNotify: 更新订单的时候发生异常:该字符串未被识别为有效的 DateTime

<time_end><![CDATA[20150803230817]]></time_end>

这一步,我直接写DateTime.Parse转换的,抛异常,后来改写为DateTime.ParseExact方法,解决问题,注意format是yyyyMMddHHmmss,不明白为什么HH也要大写,不然也报错。

DateTime payDate = notifyData.IsSet("time_end") ? DateTime.ParseExact(notifyData.GetValue("time_end").ToString(), "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture) : DateTime.MinValue;

改了以后,抛出的异常是 更新订单的时候发生异常:正在中止线程在 System.Threading.Thread.AbortInternal(),这个百思不得琪姐。百度搜索一般是Response.Redirect和Server.Transfer导致线程终止,也没找到类似的问题。一行一行过代码发现以下Bug.

【坑6】微信支付的单位是分,一般网站单位是元。而且微信的total_fee不能接收小数点,不能是0.1分钱。

我的更新订单程序有一行if (orderAmount == payAmount){}一个是微信获取到的单位是分,一个是网站的,单位是元,这个坑也浪费了好久时间,一行一行过代码才发现,因为是逻辑错误。幸好有这个判断,否则钱相差100倍,天大的BUG。

这个BUG改好以后,订单状态被成功的更新了。

微信做的比较人性化的是,设置测试目录以及微信号白名单,测试期间,只有白名单中的微信号才能支付。部署到demo.domain.com给客户测试,测试没有问题后,部署到m.domain.com的时候,居然又报redirect_url参数错误,看到微信提示说,测试目录不能喝正式目录意义,否则会支付失败,我测试目录是http://demo.domain.com/wxpay/,正式目录是http://m.domain.com/wxpay/,难道wxpay的文件夹名称也不能一样?没道理呀,把测试目录改成其他的,还是不对。搜索了一下,恍然大悟,是【坑3】导致的。之前把网页账号的域名改为demo.domain.com了,改为m.domain.com,成功支付。注意:域名要完全匹配,程序在m.domain.com,网页账号设置domain.com一样报redirect_url参数错误。

至此,微信支付JS API调用整个流程完成,相对于支付宝Wap支付来说,花的时间更多。

总结:

1.对于第一个坑,是否有.net版,一般各种版本都会有,如果没有及时的发现.net版,用PHP去开发,那对于我来说,工作量就更大了。应该仔细的看官方各种帮助文档,也许它藏的比较深。

其实支付接口的主要逻辑,官方都做好了,重点是配置。

这里不得不说,腾讯随邮件发送的Demo下载包含各种版本网页路径,不是更好吗?

2.仔细看接口文档,先过一遍程序,自己去找潜在的问题,有利于提升分析问题的能力,如果时间紧急,请看3。

3.如果自己确定应该没有什么问题了,而没有预期工作,那么要去找出问题。

3.1 判断是不是微信端的error,在关键位置加日志,微信的demo中,可以设置输入Log的级别,测试的时候输出debug,Info,error,正式环境可以设置只输出error,这一点很赞。

3.2 自己代码的BUG: 整段代码加try...catch,把异常信息保存到日志中去,这样能快速的找出问题。try catch不用多说了,标配。

3.3 异常容易捕获,如果是逻辑错误,需要细心的过代码。

主要精简:

官方demo,先跳转到example/ProductPage.aspx,这个页面主要是调用【网页授权获取用户信息】接口获取用户的openid,点击按钮的时候,跳转到JsApiPayPage.aspx页面,传递openid和total_fee支付金额过去,其中用ViewState保存openid是个槽点,web app尽量不要用ViewState和服务器控件,它们会生成臃肿的HTML,增加网络流量,影响加载速度,你要知道,手机如果是在GSM网络下访问站点,多一些文本都是压力,尽可能精简。

直接把获取openid的逻辑写到JsApiPayPage页面就好了,省的多跳转一个页面,后台代码是要验证授权,然后获取到前台JS API调用需要的参数wxJsApiParam。

public partial class JsApiPayPage : BaseOnlineSend
    {
        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)
            {
                JsApiPay jsApiPay = new JsApiPay(this);
                jsApiPay.GetOpenidAndAccessToken();

                string openid = jsApiPay.openid; ;

                OrderDetail = this.Detail;
                //付款金额
                decimal total_fee = OrderDetail.TotalOrderAmount + OrderDetail.TotalLogisticsFee + OrderDetail.OrderAmountRevise + OrderDetail.LogisticsFeeRevise;
                //检测是否给当前页面传递了相关参数
                if (string.IsNullOrEmpty(openid) || total_fee <= 0)
                {
                    Log.Error(this.GetType().ToString(), "This page have not get params, cannot be inited, exit...");
                    return;
                }

                //若传递了相关参数,则调统一下单接口,获得后续相关接口的入口参数
                jsApiPay.total_fee = (int)(total_fee * 100);//单位是分,不能有小数
                jsApiPay.orderId = this.OrderID.ToString();
                jsApiPay.siteName = this.GetConfig("SiteName");

                //JSAPI支付预处理
                try
                {
                    WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult();

                    wxJsApiParam = jsApiPay.GetJsApiParameters();//获取H5调起JS API参数
                    Log.Debug(this.GetType().ToString(), "wxJsApiParam : " + wxJsApiParam);

                }
                catch(Exception ex)
                {
                    Response.Write("<span style=‘color:#FF0000;font-size:20px‘>" + "下单失败,请返回重试" + "</span>");
                    Log.Error(this.GetType().ToString(), "下单失败," + ex.Message +";" +ex.StackTrace);
                }
            }
        }

其中,主要需要注意的是jsApiPay.total_fee,单位是分,要和自己项目的单位进行换算一些,否则会出错。

前台,页面加载之后,直接调用微信JS api 支付,支付完成后,直接在本页面显示支付结果。如果支付失败,让人家可以点击按钮尝试重新支付。

    <script type="text/javascript">

               //调用微信JS api 支付
               function jsApiCall()
               {
                   WeixinJSBridge.invoke(
                   ‘getBrandWCPayRequest‘,
                   <%=wxJsApiParam%>,//josn串
                    function (res)
                    {
                        WeixinJSBridge.log(res.err_msg);
                        if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                            document.getElementById("payFail").style.display="none";
                            document.getElementById("paySuccess").style.display="block";
                        }
                        else{
                            document.getElementById("payFail").style.display="block";
                        }
                     }
                    );
               }

               function callpay()
               {
                   //官方代码,不贴了
               }
               callpay();
     </script>

<body>
    <dl class="item_desc" id="dlPayInfo">
        <dt class="item_title"><span class="txt">支付信息</span></dt>
        <dd class="item_panel pl1">
            <span class="title"><%=this.OrderDetail.ProductNames %></span>
        </dd>
        <dd class="item_panel pl1">
            <span class="title">订单号:</span><span class="selected com_c4"><%=this.OrderID %></span>
        </dd>
        <dd class="item_select item_last">
            <div class="title">
                <strong>应付金额: </strong><span class="com_c4"><%=OrderDetail.TotalOrderAmount + OrderDetail.TotalLogisticsFee + OrderDetail.OrderAmountRevise + OrderDetail.LogisticsFeeRevise %> 元</span>
            </div>
        </dd>
    </dl>
    <br />
    <dd class="item_select" id="paySuccess" style="display:none">
        <div class="title" style="padding-left:3rem">
            <img src="/images/onSuccess.gif" title="支付成功" />
            <span class="selected"><b class="big">支付成功!</b><br />
                系统正在处理收款,订单状态可能会有1-5分钟的滞后,感谢您的耐心等待。<br />
                <a href="/member/order/info1/">查看订单</a><br /><br />
                您还可以:<a href="/">继续购物</a><br /><br />
                <br /><br />
            </span>
        </div>
    </dd>
    <dd class="item_select"id="payFail" style="display:none">
        <div class="title item" style="padding-left:2.0rem">
            <span class="selected"><b class="big">支付失败!</b></span>
            <div class="btns" style="margin-top:10px"><a class="com_btn_7" style="padding:1px;cursor:pointer;" onclick="callpay()">重新支付</a></div>
        </div>
        <div class="title item" style="padding-left:2.0rem">
            <span class="selected">
                您可以查看微信交易记录。如果没有扣费,可以稍后尝试重新支付。如果已经扣费,请拨打客服电话联系我们
                <br /><br />
                如果多次重新支付还是遇到了问题,稍后您可以在登陆状态下,访问个人中心-><a href="/member/order/">我的订单</a>,为编号为<%=this.OrderID %>的订单付款,有多种支付方式供您选择
                ...
            </span>
        </div>
    </dd>
</body>

 

时间: 2024-10-12 17:38:44

微信支付.NET版开发总结(JS API),好多坑,适当精简的相关文章

微信支付.NET版开发总结(JS API),好多坑,适当精简。

前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下.接下来,按照开发步骤,细数一下,我遇到的那些坑. [坑1]官方邮件中下载的demo只有PHP版本,其他版本没有给链接.可能让人误以为只有PHP版本,事实上,各种版本都有. 拿到了腾讯发给客户的,微信支付商户资料,邮件中提示:证书的详细使用方案,请查看微信支付开发接口文档.根据邮件微信支付开发接口文档的链接,定向到一个新的邮件附件,里面的内容: 3. 使用公众号发起支付请求 使用JS API在微信的网页中发起支付请求,详细方法见文档中

微信支付.NET版开发总结,好多坑

前2天,做一个手机网页的微信支付的项目,费了好些周折,记录一下. [坑1]官方邮件中下载的demo只有PHP版本,其他版本没有给链接.可能让人误以为只有PHP版本,事实上,各种版本都有. 拿到了腾讯发给客户的,微信支付商户资料,邮件中提示:证书的详细使用方案,请查看微信支付开发接口文档.根据邮件微信支付开发接口文档的链接,定向到一个新的邮件附件,里面的内容: 3. 使用公众号发起支付请求 使用JS API在微信的网页中发起支付请求,详细方法见文档中有关JS API的章节. 微信支付接口文档及de

微信公众平台开发(103) JS API支付

本文介绍如何使用JS API支付接口完成微信支付. 一.JS API支付接口(getBrandWCPayRequest) 微信JS API只能在微信内置浏览器中使用,其他浏览器调用无效.微信提供getBrandWCPayRequest接口供商户前端网页调用,调用之前微信会鉴定商户支付权限,若商户具有调起支付的权限,则将开始支付流程.这里主要介绍支付前的接口调用规则,支付状态消息通知机制请参加下文.接口需要注意:所有传入参数都是字符串类型! getBrandWCPayRequest参数如表6-5所

微信支付开发(1) JS API支付

关键字:微信支付 微信支付v3 jsapi支付 统一支付 Native支付 prepay_id 作者:方倍工作室 原文: http://blog.csdn.net/pondbay/article/details/40536677 本文介绍微信支付下的jsapi实现流程 前言 微信支付现在分为v2版和v3版,2014年9月10号之前申请的为v2版,之后申请的为v3版.V3版的微信支付没有paySignKey参数.v2的相关介绍请参考方倍工作室的其他文章.本文介绍的微信支付v3. 流程实现 1. O

微信支付v3版-微信支付开发教程

微信支付现在分为v2版和v3版,2014年9月10号之前申请的为v2版,之后申请的为v3版.V3版的微信支付没有paySignKey参数. 微信支付v3 提示:因微信支付商户平台升级,若您在资料审核通过后,收到支付小助手发送的邮件通知为以下信息,请按本页面接口文档进行支付开发.1. 信息包括:商户ID.申请编号.登录帐号.登录密码.商户API密码2..证书包括:商户API证书.证书密钥.CA证书 1. 使用网页授权接口 使用网页授权接口获取用户的基本信息. [微信公众号]OAuth2.0授权.p

微信公众号可通过现金红包接口发放微信支付现金红包(附开发教程)

农历新年将至,支付宝红包打了一仗,微信在朋友圈屏蔽了它的分享,但单防守还不行,进攻才是最好的防守.昨日,微信支付现金红包接口正式开放,只需开通微信支付,即可接入现金红包.微信公众号也可以发放现金红包了! 通过现金红包接口,公众号开发者可以策划相关运营活动,向用户发放微信支付现金红包,更好的达到品牌推广及回馈用户的效果. 1.商户调用接口时,通过指定发送对象以及发送金额的方式发放红包,这样的方式,允许商户灵活的应用于各种各样丰富的活动场景 2.领取到红包后,用户的资金直接进入微信零钱,避免繁复的领

微信支付服务端开发

前言 最近应公司业务需求,把微信支付完成了,当然已经顺利上线.但是开发的过程是也是踩了很多坑,下面我就先说说开发流程,以及在开发中遇到的大大小小的坑. 开发流程 首先,看一下微信开方平台关于支付的一个时序图,如下: 微信支付时序图https://pay.weixin.qq.com/wiki/doc/api/app/app.php 商户系统和微信支付系统主要交互说明: 步骤1:用户在商户APP中选择商品,提交订单,选择微信支付. 步骤2:商户后台收到用户支付单,调用微信支付统一下单接口.参见[统一

微信支付h5客户端开发步骤

第一步:用户同意授权,获取code 在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下 服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),引导关注者打开如下页面: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&s

微信支付----维权接口开发!(转掌眼)

最近比较忙,没多少时间写!所以这篇可能比较乱,请理解.. 1.你需确定维权URL通知地址: 在“商户功能→商户信息→修改→维权通知URL”查看维权通知URL.(区分大小写) 2.添加用户维权入口 在服务号自定义菜单添加名称叫“维权”的菜单,该菜单不分层级,不分位置,微信自动跳转到维权页面.. 3.获取维权通知XML数据. 在ResponseHandler类(微信支付----没我想的那么难)添加获取XML参数的方法: /**获取XML参数**/ public string getMpParamet