【支付流程】

1.小程序内调用登录接口,获取到用户的openid(我们这一步骤让前端去获取)

2.服务端代码这边生成订单

3.服务端调用支付统一下单的api

4.服务端将再次签名,返回5个参数(前端得到数据后可以调起支付)

5.微信后台会回调我们服务端,我们通过回调更新订单状态

6.前端也会调用服务端订单查询接口,服务端查询订单状态(防止微信回调这边的一个时间差),如果成功了,在这个接口里会向用户发送一个小程序的模板消息(会消耗一个第3步的prepay_id,后续写模板消息的时候会说)

[ 概述 ]

重点是步骤3和4,特别是签名那块的格式要求务必按照微信的要求来。

【流程详解】

【 1.统一下单 】

目的:在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。

接口:

https://api.mch.weixin.qq.com/pay/unifiedorder

请求参数

字段名 变量名 必填 类型 示例值 描述
小程序ID appid String(32) wxd678efh567hg6787 微信分配的小程序ID
商户号 mch_id String(32) 1230000109 微信支付分配的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,长度要求在32位以内。推荐随机数生成算法
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 通过签名算法计算得出的签名值,详见签名生成算法
签名类型 sign_type String(32) MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
商品描述 body String(128) 腾讯充值中心-QQ会员充值

商品简单描述,该字段请按照规范传递,具体请见参数规定

商品详情 detail String(6000)   商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见“单品优惠参数说明”
附加数据 attach String(127) 深圳分店 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
商户订单号 out_trade_no String(32) 20150806125346 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。详见商户订单号
标价币种 fee_type String(16) CNY 符合ISO 4217标准的三位字母代码,默认人民币:CNY,详细列表请参见货币类型
标价金额 total_fee Int 88 订单总金额,单位为分,详见支付金额
终端IP spbill_create_ip String(16) 123.12.12.123 APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
交易起始时间 time_start String(14) 20091225091010 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
交易结束时间 time_expire String(14) 20091227091010

订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。订单失效时间是针对订单号而言的,由于在请求支付的时候有一个必传参数prepay_id只有两小时的有效期,所以在重入时间超过2小时的时候需要重新请求下单接口获取新的prepay_id。其他详见时间规则

建议:最短失效时间间隔大于1分钟

订单优惠标记 goods_tag String(32) WXG 订单优惠标记,使用代金券或立减优惠功能时需要的参数,说明详见代金券或立减优惠
通知地址 notify_url String(256) http://www.weixin.qq.com/wxpay/pay.php 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
交易类型 trade_type String(16) JSAPI 小程序取值如下:JSAPI,详细说明见参数规定
商品ID product_id String(32) 12235413214070356458058 trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
指定支付方式 limit_pay String(32) no_credit 上传此参数no_credit--可限制用户不能使用信用卡支付
用户标识 openid String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。openid如何获取,可参考【获取openid】。

[ 统一下单的注意点 ]

1.签名sign生成算法,详见https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3

2.随机字符串nonce_str,可以用加入当前时间戳+随机数的方法来生成

3.交易类型trade_type,小程序是JSAPI

4.统一下单和接下来的再次签名的签名类型sign_type,都统一使用MD5加密,不然可能会出现验证签名失败的情况,注意这是一个大坑。

[简易代码示例]

//第1步:拼接对应的参数
Map<String, String> param = new TreeMap<>();
param.put("appid", Config.MINI_PROGRAM_APP_ID); //像这些值,最好有个微信config类来存
param.put("mch_id", Config.MCH_ID);
param.put("openid", openId);
param.put("attach", orderDesc);
param.put("body", orderDesc);
param.put("detail", orderDesc);
param.put("limit_pay", Config.NO_CREDIT_LIMIT_PAY);
param.put("nonce_str", nonceStr);
param.put("notify_url", Config.UNIFIED_ORDER_NOTIFY_RELATIVE_URL);
param.put("out_trade_no", outTradeNo);
param.put("spbill_create_ip", clientIp);
param.put("total_fee", String.valueOf(totalFee));
param.put("trade_type", tradeType);
param.put("sign_type","MD5");
//第2步:生成签名
StringBuilder urlParam = new StringBuilder();
for (String paramKey : param.keySet()) { //排序
urlParam.append(paramKey).append("=").append(param.get(paramKey)).append("&");
}
String preParam = urlParam.toString().substring(, urlParam.toString().length() - ); //拼接的urlParam最后有一个&,删除
String finalParam = preParam + "&key=" + WeiXinConfig.PRIVATE_KEY; //key不参与排序
String sign = MD5.sign(finalParam, Const.Charset.UTF8).toUpperCase(); //排序后的参数+key 进行MD5签名,并且全部大写 //第三步:方便后续生成xml格式请求体,简易用一个类来封装对应的参数,然后返回
request.setAppId(param.get("appid"));
request.setSign(sign);
//request.set...其他参数,但要额外加一个成员变量存储sign

[ 返回结果 ]

字段名 变量名 必填 类型 示例值 描述
返回状态码 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息 return_msg String(128) 签名失败

返回信息,如非空,为错误原因

签名失败

参数格式校验错误

以下字段在return_code为SUCCESS的时候有返回

字段名 变量名 必填 类型 示例值 描述
小程序ID appid String(32) wx8888888888888888 调用接口提交的小程序ID
商户号 mch_id String(32) 1900000109 调用接口提交的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为请求支付的终端设备号等
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 微信返回的随机字符串
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 微信返回的签名值,详见签名算法
业务结果 result_code String(16) SUCCESS SUCCESS/FAIL
错误代码 err_code String(32) SYSTEMERROR 详细参见下文错误列表
错误代码描述 err_code_des String(128) 系统错误 错误信息描述

以下字段在return_code 和result_code都为SUCCESS的时候有返回

字段名 变量名 必填 类型 示例值 描述
交易类型 trade_type String(16) JSAPI 交易类型,取值为:JSAPI,NATIVE,APP等,说明详见参数规定
预支付交易会话标识 prepay_id String(64) wx201410272009395522657a690389285100 微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时
二维码链接 code_url String(64) URl:weixin://wxpay/s/An4baqw trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付

【2.再次签名】

统一下单后,需要再次签名后,才能将数据返回给前端,不然会出现前端能调起微信支付,但是在支付过程中一直报签名失败的提示。

再次签名无需请求微信后台,只是自己对统一下单的一些参数做一次生成签名而已。

[ 再起签名需要的参数 ]

字段名 变量名 必填 类型 示例值 描述
小程序ID appId String wxd678efh567hg6787 微信分配的小程序ID
时间戳 timeStamp String 1490840662 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
随机串 nonceStr String 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
数据包 package String prepay_id=wx2017033010242291fcfe0db70013231072 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=wx2017033010242291fcfe0db70013231072
签名方式 signType String MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致

举例如下:(必须和这里的格式一致,红色部分的也一样!)

paySign = MD5(appId=wxd678efh567hg6787&nonceStr=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&package=prepay_id=wx2017033010242291fcfe0db70013231072&signType=MD5&timeStamp=1490840662&key=qazwsxedcrfvtgbyhnujmikolp111111)

[ 简易代码示例 ]

//第1步:拼接对应的参数
Map<String, String> param = new TreeMap<>();
String nonceStr = WeiXinPayUtils.generateNonceStr(); //专门写了个方法来生成随机字符串
param.put("appId", Config.MINI_PROGRAM_APP_ID);
param.put("package", "prepay_id="+prepayId); //从统一下单响应的结果中取的参数
param.put("nonceStr", nonceStr);
param.put("timeStamp", String.valueOf(System.currentTimeMillis() / )); //秒级别的时间戳,应该毫秒也OK
param.put("signType","MD5"); //小程序,这里和统一下单的签名类型保持一致
//第2步:再次生成签名
StringBuilder urlParam = new StringBuilder();
for (String paramKey : param.keySet()) {
urlParam.append(paramKey).append("=").append(param.get(paramKey)).append("&");
}
String preParam = urlParam.toString().substring(, urlParam.toString().length() - );
String finalParam = preParam + "&key=" + Config.PRIVATE_KEY;
String sign = MD5.sign(finalParam, Const.Charset.UTF8).toUpperCase();
//同理,这里建议做一个响应参数给前端
需要返回给前端的参数有:
response.setSign(sign);
response.setAppId(param.get("appId"));
response.setPrepayId(weiXinUnifiedOrderResponse.getPrepayId); //统一下单的响应数据
response.setNonceStr(param.get("nonceStr"));
response.setTimeStamp(param.get("timeStamp"));
response.setPayWay(Const.PayWay.WEIXIN);
response.setAmount(amount);
response.setSignType("MD5");
response.setOrderNo(outTradeNo);
response.setCodeUrl(weiXinUnifiedOrderResponse.getCodeUrl());//统一下单的响应数据

再次签名之后,前端就可以根据服务端返回的参数发起正常的微信支付了。

【3.前端调微信支付需要的参数(即服务端响应参数必传参数)】

参考文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3

前端调用wx.requestPayment(OBJECT)发起微信支付

注意:里面的时间戳timeStamp,nonceStr,package,signType,paySign都是服务端的参数,不是前端自己生成的随机数,注意!!!

要理解微信那边也只是根据这些数据来生成签名,会与我们再次签名生成的签名(即paySign)做一次比较,而这个paySign就是由这几个参数加密生成的,自己做项目时没有清楚意识到这一点,时间戳传给前端有误导致一直签名失败,这里是个坑,要注意。

Object参数说明:

参数 类型 必填 说明
timeStamp String 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
nonceStr String 随机字符串,长度为32个字符以下。
package String 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
signType String 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
paySign String 签名,具体签名方案参见微信公众号支付帮助文档;
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

回调结果:

回调类型 errMsg 说明
success requestPayment:ok 调用支付成功
fail requestPayment:fail cancel 用户取消支付
fail requestPayment:fail (detail message) 调用支付失败,其中 detail message 为后台返回的详细失败原因

示例代码(前端代码):

wx.requestPayment(
{
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){
},
'fail':function(res){},
'complete':function(res){
}
})

【微信小程序官方参考】

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

01_微信小程序支付的更多相关文章

  1. 微信小程序支付步骤

    http://blog.csdn.net/wangsf789/article/details/53419781 最近开发微信小程序进入到支付阶段,一直以来从事App开发,所以支付流程还是熟记于心的.但 ...

  2. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

  3. Java 后端微信小程序支付demo (网上说的坑里面基本上都有)

    Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...

  4. php对接微信小程序支付

    前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...

  5. 微信小程序支付遇到的坑

    1,微信公众号支付和微信小程序支付有差异 微信公众号:可以直接跳转走h5的微信支付 微信小程序:在测试环境.沙箱环境使用微信公众号的跳转支付没有问题,在线上存在支付异常 最后商讨的解决方法 openi ...

  6. 微信小程序支付接入注意点

    一.微信支付后台服务器部署 服务器采用ubuntu16.04 + php7.0 + apache2.0. 微信支付后台服务使用了curl 和 samplexml ,因此php.ini配置中必须开启这两 ...

  7. 微信小程序支付开发之申请退款

    微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...

  8. 微信小程序支付接入实战

    1. 微信小程序支付接入实战 1.1. 需求   最近接到一个小程序微信支付的需求,需要我写后台支持,本着能不自己写就不自己写的cv原则,在网上找到了些第三方程序,经过尝试后,最后决定了这不要脸作者的 ...

  9. 微信小程序支付异常:requestPayment:fail no permission

    今天在调试微信小程序支付时碰到了这个问题,支付参数都正常生成了,在调用 wx.requestPayment 进行支付时遇到了这个报错,查了一下发现是开发者工具中 AppID 写错了,用的 AppID ...

随机推荐

  1. ONTAK2010 Peaks加强版(离线&在线)

    题面 弱化版:luogu 强制在线版:bzoj 题解 本题有两种解法 离线算法:线段树合并 先看一道简单题[USACO18JAN]MooTube 本题就是在此基础上求第\(k\)高的点 首先把询问和路 ...

  2. Sum(欧拉降幂+快速幂)

    Input 2 Output 2 Hint 1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cas ...

  3. 2018牛客多校2 - J farm 随机乱搞/二进制分组

    题意:给定n*m的格子,每个格子有不同的种类,q次操作,每次操作使[x1,y1]到[x2,y2]的格子除了k类型的以外都删除,最后单次询问所有格子被删了几个 官方题解提到了两种有意思的做法,随机和二进 ...

  4. Docker 镜像加速

    通过 Docker 官方镜像加速,中国区用户能够快速访问最流行的 Docker 镜像.该镜像托管于中国大陆,本地用户现在将会享受到更快的下载速度和更强的稳定性,从而能够更敏捷地开发和交付 Docker ...

  5. 学习总结 —— python

    1.了解python 学习python 3 入门知识 python  库 .包  .模块 2.了解pycharm Pycharm 导入 Python 包.模块 pycharm 快捷键 3.了解djan ...

  6. 动态时间规整DTW(Dynamic Time Warping )

    动态时间规整DTW(Dynamic Time Warping ) 原文:https://blog.csdn.net/raym0ndkwan/article/details/45614813 算法笔记- ...

  7. 后缀自动机 && 题目

    因为明天要讲解后缀自动机了,所以只能抱抱佛脚,临时做做题目.其实很久以前看过,但是不太懂,看的是clj的原文,不太懂.现在只能临时看看是怎么弄的,应付下. ---------------------- ...

  8. ASP.NET实现数据绑定

    一.数据绑定语法 数据绑定表达式包含在“<%#”和“%>”分隔符之内,并使用Eval方法和Bind方法.Eval方法用于定义单向(只读)绑定,Bind方法用于定义双向(可更新)绑定. 语法 ...

  9. VirtualBox 命令行操作

    vboxmanage list vmsvboxmanage list runningvmsvboxmanage startvmvboxmanage controlvm "RHEL6.1_fo ...

  10. bug缺陷级别定义

    缺陷定义: 出现以下缺陷测试定义为致命 bug l  系统无响应处于死机状态. l  点击某个菜单后出现“The page cannot be displayed”或者返回异常错误. l  进行某 ...