zoukankan      html  css  js  c++  java
  • 微信JSAPI支付 跟 所遇到的那些坑

    首先介绍一下我在调用微信支付接口使用的是 weixin.senparc SDK,非常方便好用开源的一个微信开发SDK。

    weixin.senparc SDK 官网:http://weixin.senparc.com/

    先去下载下来Senparc.Weixin SDK。

    在调起支付接口之前,需要先要调用统一下单接口,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。

     微信 JsApi支付 在这个目录下 Senparc.Weixin.MP.Sample.Controllers 找到JsApi支付。

    public ActionResult JsApi(string code, string state)
            {
                if (string.IsNullOrEmpty(code))
                {
                    return Content("您拒绝了授权!");
                }
    
                if (!state.Contains("|"))
                {
                    //这里的state其实是会暴露给客户端的,验证能力很弱,这里只是演示一下
                    //实际上可以存任何想传递的数据,比如用户ID,并且需要结合例如下面的Session["OAuthAccessToken"]进行验证
                    return Content("验证失败!请从正规途径进入!1001");
                }
                try
                {
    
    
                    //获取产品信息
                    var stateData = state.Split('|');
                    int productId = 0;
                    ProductModel product = null;
                    if (int.TryParse(stateData[0], out productId))
                    {
                        int hc = 0;
                        if (int.TryParse(stateData[1], out hc))
                        {
                            var products = ProductModel.GetFakeProductList();
                            product = products.FirstOrDefault(z => z.Id == productId);
                            if (product == null || product.GetHashCode() != hc)
                            {
                                return Content("商品信息不存在,或非法进入!1002");
                            }
                            ViewData["product"] = product;
                        }
                    }
    
                    //通过,用code换取access_token
                    var openIdResult = OAuthApi.GetAccessToken(TenPayV3Info.AppId, TenPayV3Info.AppSecret, code);
                    if (openIdResult.errcode != ReturnCode.请求成功)
                    {
                        return Content("错误:" + openIdResult.errmsg);
                    }
    
                    string sp_billno = Request["order_no"];
                    if (string.IsNullOrEmpty(sp_billno))
                    {
                        //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
                        sp_billno = string.Format("{0}{1}{2}", TenPayV3Info.MchId, DateTime.Now.ToString("yyyyMMdd"),
                            TenPayV3Util.BuildRandomStr(10));
                    }
                    else
                    {
                        sp_billno = Request["order_no"];
                    }
    
                    var timeStamp = TenPayV3Util.GetTimestamp();
                    var nonceStr = TenPayV3Util.GetNoncestr();
    
                    var body = product == null ? "test" : product.Name;
                    var price = product == null ? 100 : product.Price * 100;
                    var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, body, sp_billno, price, Request.UserHostAddress, TenPayV3Info.TenPayV3Notify, TenPayV3Type.JSAPI, openIdResult.openid, TenPayV3Info.Key, nonceStr);
                    var result = TenPayV3.Unifiedorder(xmlDataInfo);//调用统一订单接口
    
                    //JsSdkUiPackage jsPackage = new JsSdkUiPackage(TenPayV3Info.AppId, timeStamp, nonceStr,);
                    var package = string.Format("prepay_id={0}", result.prepay_id);
    
                    ViewData["appId"] = TenPayV3Info.AppId;
                    ViewData["timeStamp"] = timeStamp;
                    ViewData["nonceStr"] = nonceStr;
                    ViewData["package"] = package;
                    ViewData["paySign"] = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key);
    
                    return View();
                }
                catch (Exception ex)
                {
                    var msg = ex.Message;
                    msg += "<br>" + ex.StackTrace;
                    msg += "<br>==Source==<br>" + ex.Source;
    
                    if (ex.InnerException != null)
                    {
                        msg += "<br>===InnerException===<br>" + ex.InnerException.Message;
                    }
                    return Content(msg);
                }
            }

    先在微信服务后台生成预支付交易单,获得预支付订单号。

    先说说在统一下单这里遇到的坑。

    1.在统一下单的时候解析返回结果,一直出现以下问题:您没有JSAPI支付权限

    <xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[您没有JSAPI支付权限]]></return_msg>
    </xml>

    1)先看看你的公众号微信支付设置是否正确。

    关于如何配置微信支付:可以参考这个 http://jingyan.baidu.com/article/77b8dc7fef360d6174eab690.html

    2)检查你的授权目录是否正确,格式要这样,后面记得别漏了一个/   例如:http://test.cn/u/

    3)检查需要传过去的账户参数,上公众号还有商户号检查你的账户参数是否正确。我在开发当中就出现,微信公众号商户号,appid 是分别不同两个公众号的,坑啊,找了好久,觉得不对劲,原来是给的配置参数密钥不对。

     这里详细说一下对应的参数:

    MCHID:商户号(必须配置,开户邮件中可查看),商户申请微信支付后,由微信支付分配的商户收款账号。

    APPID:微信开放平台审核通过的应用APPID,appid是微信公众账号或开放平台APP的唯一标识,在公众平台申请公众账号或者在开放平台申请APP账号后,微信会自动分配对应的appid用于标识该应用。可在微信公众平台-->开发者中心查看,商户的微信支付审核通过邮件中也会包含该字段值.

    KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置),交易过程生成签名的密钥,仅保留在商户系统和微信支付后台,不会在网络中传播。商户妥善保管该Key,切勿在网络中传输,不能在其他客户端中存储,保证key不会被泄漏。商户可根据邮件提示登录微信商户平台进行设置。也可按一下路径设置:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置.
    APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置)

    2.在统一下单,解析返回来的结果我出现了商户号mch_id与appid不匹配这个问题

    <xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[商户号mch_id与appid不匹配]]></return_msg>
    </xml>

    原因是我拿到的商户号不是这个公众号的。一定要检查是不是这个公众号的商户号。

    3.在统一下单,解析返回来的结果出现 appid and openid not match,appid和openid不匹配。

    <xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[appid and openid not match]]></return_msg>
    </xml>

    原因是我这个用户的openid 不是这个公众号的

    3.在统一下单,解析返回来的结果出现 CDATA[openid is invalid],openid无效

    <xml>
    <return_code><![CDATA[FAIL]]></return_code>
    <return_msg><![CDATA[openid is invalid]]></return_msg>
    </xml>

    原因是,传过去不是有效的opendid。不小心看错了,把用户id 当做openid传过去了。

    当统一下单成功,会返回以下格式的参数

    <xml>
       <return_code><![CDATA[SUCCESS]]></return_code>
       <return_msg><![CDATA[OK]]></return_msg>
       <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
       <mch_id><![CDATA[10000100]]></mch_id>
       <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
       <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
       <result_code><![CDATA[SUCCESS]]></result_code>
       <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
       <trade_type><![CDATA[APP]]></trade_type>
    </xml>

    解析获得预支付单号:

    string prepayId = res.Element("xml").Element("prepay_id").Value; //获取预支付订单号

    给页面对应地参数

                    ViewData["appId"] = TenPayV3Info.AppId;
                    ViewData["timeStamp"] = timeStamp;
                    ViewData["nonceStr"] = nonceStr;
                    ViewData["package"] = package;
                    ViewData["paySign"] = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key);

    静态页面js调用:

    wx.chooseWXPay({
        timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
        nonceStr: '', // 支付签名随机串,不长于 32 位
        package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
        signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
        paySign: '', // 支付签名
        success: function (res) {
            if (res.err_msg == "get_brand_wcpay_request:ok") {//支付成功
     
           } else {
    //支付失败
    }
      // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。 } });
  • 相关阅读:
    springboot文件上传: 单个文件上传 和 多个文件上传
    Eclipse:很不错的插件-devStyle,将你的eclipse变成idea风格
    springboot项目搭建:结构和入门程序
    POJ 3169 Layout 差分约束系统
    POJ 3723 Conscription 最小生成树
    POJ 3255 Roadblocks 次短路
    UVA 11367 Full Tank? 最短路
    UVA 10269 Adventure of Super Mario 最短路
    UVA 10603 Fill 最短路
    POJ 2431 Expedition 优先队列
  • 原文地址:https://www.cnblogs.com/huangenai/p/6265776.html
Copyright © 2011-2022 走看看