zoukankan      html  css  js  c++  java
  • 微信公众号支付开发,希望能帮到大家

    文档真的很重要,不管是写还是看的人都应该认真点

    本文主要写给公众平台h5支付开发者

    真的,区分大小写,注意前面的参数就很少会出现问题了。

    除了博客园,这篇文章的内容也放在这里自己的blog 【http://mimeay.cc/】

    一、技术栈

    • 语言:Node
    • web框架 Express
    • 开发过程中依赖的模块
      1. express-xml-bodyparser 用于解析客户端post过来的xml格式的数据
      2. jstoxml 用于将js对象转换成xml
      3. xml2js 用户将xml转换js对象

     

    二、微信开发之旅

      1. 注册商户平台

         这一步不设计开发。。。不详说。

      2. 支付目录设置

         微信公众平台-> 微信支付-> 开发配置,见微信官方图,具体细节见图片

    alt

      3. 统一下单

        接口地址 :https://api.mch.weixin.qq.com/pay/unifiedorder

    必须提交的参数

     appid 公众平台的appid
     attach 自定义消息
     body 商品类别【商品信息都可以】
     mch_id 商户平台的账号
     nonce_str 随机字符串,不超过32位
     notify_url 微信生成prepay_id后,会发送请求到所设置的回调地址
     out_trade_no 商户自定义生成的订单号,要保证不能重复
     spbill_create_ip 客户端的ip地址
     total_fee 支付的金额,以分为单位
     trade_type 交易类型 取值有JSAPI,NATIVE,APP ,因为是在h5页面触发支付,我选择了 JSAPI,要根据实际需求选择
    

    根据项目,需要提交的参数

     openid 标示用户的id 【下面会贴相关链接】,如果是h5支付开发就一定要传
    

        以上提交参数要注意区分大小写【如果有大写的话】,针对几个参数说明一下 openid :用户授权后,微信会在你设置的授权回调域名后拼接code参数,通过这个code的值,然后通过code换取网页授权accesstoken。    

        openid。请注意,这里需要通过网页授权获取
        mch_id :注册商户平台后,微信会把商户号和密码发到指定的邮箱,这里用到商户账号而已

      4.代码

    看代码啦

        后端代码

        为了展示,我把内容整合成在一起,实际开发并没有写在一起

      let config = {
        appid : '这里是appid',
        mch_id : '商户平台账号'
        notify_url : 'http://mimeay.cc/pay/receive',
        key : '在商户平台设置的'
     }
    
     let util = {
      createNonceStr () {
        return Math.random().toString(36).substr(2, 15);
      },
      createTimestamp  () {
        return parseInt(new Date().getTime() / 1000) + '';
      },
      raw (args) {
        let keys = Object.keys(args);
        keys = keys.sort()
        let newArgs = {};
        keys.forEach(function (key) {
          newArgs[key] = args[key];
        });
        let string = '';
        for (let k in newArgs) {
          string += '&' + k + '=' + newArgs[k];
        }
        string = string.substr(1);
        return string;
      },
      paySign (data,key) {
        let stringA,stringSignTemp,sign;
        stringA = module.exports.raw(data);
        stringSignTemp = stringA +'&key=' + key;
        sign = md5(stringSignTemp).toUpperCase();
        return sign;
      },
      post_request_xml(url,data){
        // 这里返回响应的内容
      }
     }

        生成 prepay_id

    unified_order ({openid,ip,out_trade_no,total_fee,category = '纪念品',trade_type = 'JSAPI',device_info = 'WEB',attach = '网上商城'}){  
        let baseUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        let nonce_str = util.createNonceStr();
        // ip 可以从请求对象取
        // openid 通过客户端传递
        // out_trade_no 请求统一下单前先生成【不管用户最终是否完成支付】
        // total_fee 支付金额,单位为分,通过商品的id从数据库获取价格并转化成分【前端传递金额不可靠】
        // 其他参数不传则默认
        let data = {
          appid : config.appid,
          attach : attach,
          body : '公司名-' + category,
          mch_id : config.mch_id,
          nonce_str: nonce_str,
          notify_url : config.notify_url,
          openid : openid,
          out_trade_no : out_trade_no,
          spbill_create_ip : ip,
          total_fee:total_fee,
          trade_type : trade_type,
          device_info : device_info
        };
        let sign  = util.paySign(data,config.key);
        data['sign'] = sign;
        let xmlData = {
          xml : data
        }
        //jstoxml.toXML 是把js转换成xml的一个方法来的
        let xml = jstoxml.toXML(xmlData);
        // post_request_xml 
        return util.post_request_xml(baseUrl,xml).then((result)=>{
          const {sign,prepay_id,return_code,return_msg} = result;
          if(return_code == 'FAIL'){
            return {
              return_code,
              return_msg
            }
          }else{
            return {
              return_code,
              return_msg,
              prepay_id : prepay_id
            }
          }
        })
      }

        结合prepay_id生成客户端支付请求的参数,这里的 appId, timeStamp, nonceStr, package, signType严格区分大小写,我一开始没注意,把参数都小写了,结果导致客户端签名失败

    wx_pay_sign (prepay_id){
        let baseUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        let nonce_str,data,sign,timestamp,xmlData,xml,_package;
        nonce_str = util.createNonceStr();
        timestamp = util.createTimestamp();
        _package = 'prepay_id=' + prepay_id;
        //这里的参数要区分大小写
        data  = {
          appId : config.appId,
          timeStamp : timestamp,
          nonceStr : nonce_str,
          package : _package,
          signType : 'MD5'
        }
        // appId, timeStamp, nonceStr, package, signType
        sign  = util.paySign(data,config.key);
        data['paySign'] = sign;
        return data;
      }

        到此,后端统一下单做的事情告一段落


        前端代码

        还记得wx_pay_sign函数做的事情吗,假设我们通过接口请求,拿到了wx_pay_sign返回的值

    $.ajax({
      url : 'xxxxxxx',
      type : 'post',
      data : {
        openid : '通过授权拿到的openid'
      },
      success (json){
       const {code,data,msg} = json;
       if(code == 0){
         wx.chooseWXPay({
           timestamp: data.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
           nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
           package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
           signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
           paySign: data.paySign, // 支付签名
           success: function (res) {
             // 支付成功后的回调函数
           }
        });
       }
      }
    })
      5. 服务端可能出现的问题
    • XML格式错误 :如果出现错误,可以在发送请求前打印在本地看下 ,格式一般如下(只展示格式,不代表这就是请求发送的参数):
      <xml>
         <appid>xxxxx</appid> 
      </xml>
    • 签名错误: 一般会出现这个问题,可能是参数值为空,如下情况【appid为空】就会导致签名失败(只展示格式,不代表这就是请求发送的参数)
     <xml>
         <appid></appid>
         <mch_id>23123123</mch_id> 
     </xml>
      6. 客户端调试可能出现的问题
    • 支付签名失败 :正常来说是 appId, timeStamp, nonceStr, package, signType 签名的时候出现问题,一有可能是没有区分大小写,要么就是参数的值设置错误,参与签名的时候key一定要正确,如果没有的话,可以在商户平台设置
      7. 部分参考地址

    三  联系我

       因为是为了展示给大家看,所以对代码有所修改,可能会出现错误,请大家理解。大家如果在做微信h5支付开发过程中有遇到问题,可加我qq【200909050】,我尽自己能力帮忙。

  • 相关阅读:
    .NET程序员应该知道些什么[转载]
    天气数据一把抓。
    粮食的存在
    asp.net 开发 跬步篇〔1〕_ajax web页面复杂处理延时、客户交互问题
    Asp .net +jquery +.ashx 文件实现分页
    深入理解C++中的某些基本概念
    C++ 函数形参与实参总结
    Hash算法学习小记(一)
    关于指针和句柄的一些小记
    子类别忘了父类的带参构造函数!!!
  • 原文地址:https://www.cnblogs.com/mimeay/p/6070303.html
Copyright © 2011-2022 走看看