美文网首页
【微信支付】公众号支付

【微信支付】公众号支付

作者: 车邮马慢 | 来源:发表于2018-08-20 20:22 被阅读0次

    一.公众号支付介绍

    公众号支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有:

    ◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付

    ◆ 用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付

    ◆ 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付

    二.支付账户

    商户在微信公众平台(申请扫码支付、公众号支付)或开放平台(申请APP支付)按照相应提示,申请相应微信支付模式。微信支付工作人员审核资料无误后开通相应的微信支付权限。微信支付申请审核通过后,商户在申请资料填写的邮箱中收取到由微信支付小助手发送的邮件,此邮件包含开发时需要使用的支付账户信息,如图2.1所示。

    图2.1 微信审核通过邮件模板

    2.1中的参数说明如2.2图所示:

    图2.2 账户参数说明

    我写微信公众号支付时,使用了mch_id、APPID、key三个参数。

    三.接口规则

    1.协议规则


    传输方式 :为保证交易安全性,采用HTTPS传输

    提交方式 :采用POST方法提交

    数据格式 :提交和返回数据都为XML格式,根节点名为xml

    字符编码 :统一采用UTF-8字符编码

    签名算法 :MD5,后续会兼容SHA1、SHA256、HMAC等。

    签名要求 :请求和接收数据均需要校验签名

    证书要求 :调用申请退款、撤销订单接口需要商户证书

    判断逻辑 :先判断协议字段返回,再判断业务返回,最后判断交易状态

    2.参数规定


    1、交易金额(重要)

    交易金额默认为人民币交易,接口中参数支付金额单位为【分】,参数值不能带小数。对账单中的交易金额单位为【元】。

    外币交易的支付金额精确到币种的最小单位,参数值不能带小数点。

    2、交易类型

    JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里

    MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口

    3、货币类型

    货币类型的取值列表:

    CNY:人民币

    4、时间

    标准北京时间,时区为东八区;如果商户的系统时间为非标准北京时间。参数值必须根据商户系统所在时区先换算成标准北京时间,例如商户所在地为0时区的伦敦,当地时间为2014年11月11日0时0分0秒,换算成北京时间为2014年11月11日8时0分0秒。

    标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

    5、时间戳(重要)

    标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

    6、商户订单号

    商户支付的订单号由商户自定义生成,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号*这些英文半角字符的组合,请勿使用汉字或全角等特殊字符。微信支付要求商户订单号保持唯一性(建议根据当前系统时间加随机序列来生成订单号)。重新发起一笔支付要使用原订单号,避免重复支付;已支付过或已调用关单、撤销(请见后文的API列表)的订单号不能重新发起支付。

    等等。。。

    3.安全规范-算法(重要)  (微信支付接口签名校验工具


    1、签名算法

    第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

    特别注意以下重要规则:

    ◆ 参数名ASCII码从小到大排序(字典序);

    ◆ 如果参数的值为空不参与签名;

    ◆ 参数名区分大小写;

    ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。

    ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段

    第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

    ◆ key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

    举例如下:

    图3.1 传送参数

    第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

    图3.2 ASCII字典序排序

    第二步:拼接API密钥:

    图3.3 拼接密钥

    最终得到最终发送的数据:

    图3.4 发送的数据

    2、生成随机数算法

    微信支付API接口协议中包含字段nonce_str,主要保证签名不可预测。我们推荐生成随机数算法如下:调用随机数函数生成,将得到的值转换为字符串。

    四.实践(重要)

    1.统一下单

    ◆ 两个必传参数 :goodsId(商品id)  openid(用户标识)

    ◆ 生成订单号封装成对象,并插入到订单表中

    图4.1 订单数据表

    ◆ 请求下单时微信必须传递的参数

    图 4.2.1 微信下单参数介绍 图 4.2.2 微信下单参数介绍

    ◆ 请求数据先插入表wxpay_request以便查询

    图 4.3 请求记录表

    ◆ 正式下单 

    WXPay wxPay =new WXPay(wxPayConfig);

    Map resp = wxPay.unifiedOrder(order);

    上两行是微信公众号支付的核心(重要)

    其中WXPayConfig这个接口需要我们自己来实现

    图 4.4 WXPayConfig接口

    上图中的5个抽象方法是需要我们自己创建MyConfig类来实现的

    其中的getCertStream()可直接返回null即可,但是getWXPayDomain()此方法实现不能返回null,否则会报如下错误:

    图 4.5 微信支付内部源码

    getWXPayDomain()方法返回的是一个IWXPayDomain接口,我们创建一个WXPayDomain类来实现这个接口,其中IWXPayDomain中的信息如下图:

    图 4.6   IWXPayDomain接口

    其中report(String s, long l, Exception e)实现但是不做处理,getDomain方法返回

    new DomainInfo(WXPayConstants.DOMAIN_API, true);即可

    此时,万事具备,只欠下单操作了:

    WXPay wxPay =new WXPay(wxPayConfig);

    Map resp = wxPay.unifiedOrder(order);

    在这个我说明一下在这里栽的坑。下单的时候,微信那边是要穿spbill_create_ip这个参数的,

    这个参数微信给的解释是:

    APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。

    我在本地测试时,获取本地IP一直报错,后来不得已,将这个参数写死,就可以了,最后写完整个功能之后将写死的放开,在测试环境上毫无问题,自豪感爆棚。。。哈哈。。

    下单成功之后,返回结果如下图所示:

    图 4.6 微信下单返回

    赶紧将微信返回的数据保存到数据库wxpay_response

    图 4.7 下单成功存库

    如果微信返回的return_code为SUCCESS,说明下单成功,如果这里没有成功就不要往后写了,赶紧回过头看看。。返回成功继续下面的操作。。

    签名

    图 4.8 微信签名

    按照微信介绍的来,记住timeStamp时间戳要以分为单位传递

    String.valueOf(System.currentTimeMillis() /1000);

    signType:MD5

    nonceStr:WXPayUtil.generateNonceStr()

    String sign = WXPayUtil.generateSignature(param, key); (重要)

    上面一句话生成签名,大功告成。。

    ◆ 微信内H5调起支付

    图 4.9 前端调微信支付所需参数

    将上一步生成的数据,以接口的方式返回给前端,前端调起微信支付即可。。

    2.支付回调

    ◆  我们在下单的时候已经将notify_url通知地址传递给了微信端,微信会回调过来

    StringwxpayResult(@Context HttpServletRequest request, @Context HttpServletResponse response);

    通过这样的方式接口微信端的回调即可。。

    Map notifyMap = WXPayUtil.xmlToMap(resultXml);

    将微信返回的数据解析成Map类型数据来做处理

    1>通过微信返回的out_trade_no(订单号)查询我们内部订单是否存在

    2>状态是否时未支付,如果以支付直接返回即可

    3>(重要)签名认证

    WXPay.isPayResultNotifySignatureValid(Map reqData)

    4>将微信返回的数据保存到wxpay_result表中

    图 4.10  微信支付回调表

    5>微信所有的处理就完了,下面就是你们自己的业务逻辑处理了。。。

    很高心和大家一起学习,当然我也是有大佬帮助过的,后期我会更新一些工作中碰到的问题,希望和大家一起进步。。

    所有的委屈,都是因为自己能力不够!! 

                                                                                            - 2018.08.23 20:44

    相关文章

      网友评论

          本文标题:【微信支付】公众号支付

          本文链接:https://www.haomeiwen.com/subject/umupeftx.html