微信支付宝一码付
- 2019 年 10 月 30 日
- 筆記
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/luo4105/article/details/80514731
路由
一码付指的是一个二维码同时指出支付宝、微信扫描并支付。
微信和支付宝支持扫描一个url二维码并通过内置的浏览器跳转。
我们可以通过js获得是来自支付宝的还是微信的浏览器,通过user-agent
,有MicroMessenger是微信,有AlipayClient是支付宝。
var ua = navigator.userAgent.toLowerCase(); if (/MicroMessenger/.test(window.navigator.userAgent)) { //微信 } else if (/AlipayClient/.test(window.navigator.userAgent)) { //支付宝 }
接着就是查看支付宝和微信中关于网页支付的教程了。
支付宝:https://docs.open.alipay.com/203/
微信: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
notice
1.网址必须以http://
或https://
开头。
流程时序图

支付宝
在一码付中,支付宝属于手机网站支付
一类。官方api地址:https://docs.open.alipay.com/203/
测试代码
@Test public void main() throws AlipayApiException { alipayClient = new DefaultAlipayClient(alipayConfig.getAlipayGateway(), alipayConfig.getAppId(), alipayConfig.getAppPrivateKey(), "json", DEFAULT_ENCODING, alipayConfig.getAppPublicKey(), SIGN_RSA); AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request alipayRequest.setReturnUrl("http://domain.com/CallBack/return_url.jsp"); alipayRequest.setNotifyUrl("http://domain.com/CallBack/notify_url.jsp"); alipayRequest.setBizContent("{" + ""out_trade_no":"fc00001"," + ""total_amount":0.01," + ""product_code":"QUICK_WAP_WAY","+ ""subject":"测试"" + "}"); AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest); if(response.isSuccess()){ System.out.println("调用成功"); System.out.println(response.getBody()); } else { System.out.println("调用失败"); System.out.println(response.getBody()); } }
支付宝API
请求地址:
环境 |
HTTPS请求地址 |
---|---|
正式环境 |
https://openapi.alipay.com/gateway.do |
公共请求参数:
参数 |
类型 |
是否必填 |
最大长度 |
描述 |
示例值 |
---|---|---|---|---|---|
app_id |
String |
是 |
32 |
支付宝分配给开发者的应用ID |
2014072300007148 |
method |
String |
是 |
128 |
接口名称 |
alipay.trade.wap.pay |
format |
String |
否 |
40 |
仅支持JSON |
JSON |
return_url |
String |
否 |
256 |
HTTP/HTTPS开头字符串 |
https://m.alipay.com/Gk8NF23 |
charset |
String |
是 |
10 |
请求使用的编码格式,如utf-8,gbk,gb2312等 |
utf-8 |
sign_type |
String |
是 |
10 |
商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 |
RSA2 |
sign |
String |
是 |
256 |
商户请求参数的签名串,详见签名 |
详见示例 |
timestamp |
String |
是 |
19 |
发送请求的时间,格式”yyyy-MM-dd HH:mm:ss” |
2014-07-24 03:07:50 |
version |
String |
是 |
3 |
调用的接口版本,固定为:1.0 |
1.0 |
notify_url |
String |
否 |
256 |
支付宝服务器主动通知商户服务器里指定的页面http/https路径。 |
https://api.xx.com/receive_notify.htm |
biz_content |
String |
是 |
– |
业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档 |
|
请求参数
参数 |
类型 |
是否必填 |
最大长度 |
描述 |
示例值 |
---|---|---|---|---|---|
subject |
String |
是 |
256 |
商品的标题/交易标题/订单标题/订单关键字等。 |
大乐透 |
out_trade_no |
String |
是 |
64 |
商户网站唯一订单号 |
70501111111S001111119 |
total_amount |
Price |
是 |
9 |
订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] |
9.00 |
支付宝还支持交易具体描述、逾期自动关闭等。
更多api详情查看官方api: https://docs.open.alipay.com/203/107090/
微信
微信,微信使用的是公众号支付
,官方api:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842,https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,微信的支付流程如下
- 微信网页授权
- 授权凭证
- 下单接口
下单详细步骤代码和api
1.获得code,等待微信回调,get请求https://open.weixin.qq.com/connect/oauth2/authorize
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数
参数 |
是否必须 |
说明 |
---|---|---|
appid |
是 |
公众号的唯一标识 |
redirect_uri |
是 |
授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 |
response_type |
是 |
返回类型,请填写code |
scope |
是 |
应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) |
state |
否 |
重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
wechat_redirect |
是 |
无论直接打开还是做页面302重定向时候,必须带此参数 |
2.获得openid,请求https://api.weixin.qq.com/sns/oauth2/access_token
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数说明
参数 |
是否必须 |
说明 |
---|---|---|
appid |
是 |
应用唯一标识,在微信开放平台提交应用审核通过后获得 |
secret |
是 |
应用密钥AppSecret,在微信开放平台提交应用审核通过后获得 |
code |
是 |
填写第一步获取的code参数 |
grant_type |
是 |
填authorization_code |
返回说明
正确的返回:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }
参数说明
参数 |
说明 |
---|---|
access_token |
接口调用凭证 |
expires_in |
access_token接口调用凭证超时时间,单位(秒) |
refresh_token |
用户刷新access_token |
openid |
授权用户唯一标识 |
scope |
用户授权的作用域,使用逗号(,)分隔 |
unionid |
当且仅当该网站应用已获得该用户的userinfo授权时,才会出现该字段。 |
3.微信预下单,请求https://api.mch.weixin.qq.com/pay/unifiedorder
{ String reqBody = WXPayUtil.mapToXml(params); byte[] bytes = LockerHttpClient.postTypedBinary("https://api.mch.weixin.qq.com/pay/unifiedorder", reqBody .getBytes(DEFAULT_ENCODING), TEXT_XML); Map<String, String> resultMap = WXPayUtil.xmlToMap(new String(bytes, DEFAULT_ENCODING)); } private Map<String, String> populateReq(String orderId, String totalFee, String openId) throws Exception { Map<String, String> params = new HashMap<>(); params.put("appid", wechatConfig.getWechatAppId()); params.put("mch_id", wechatConfig.getWechatMchId()); params.put("nonce_str", STRING_GENERATOR.generate(30)); params.put("sign_type", "MD5"); params.put("openid", openId); params.put("body", wechatConfig.getPayTitle()); params.put("total_fee", totalFee); params.put("spbill_create_ip", DEFAULT_IP); params.put("trade_type", "JSAPI"); //限制用户不能使用信用卡支付 params.put("limit_pay", "no_credit"); params.put("out_trade_no", orderId); params.put("notify_url", wechatConfig.getWechatPayNotifyUrl()); params.put("product_id", orderId); params.put("sign", WXPayUtil.generateSignature(params, wechatConfig.getWechatApiKey())); return params; }
请求参数
字段名 |
变量名 |
必填 |
类型 |
示例值 |
描述 |
---|---|---|---|---|---|
公众账号ID |
appid |
是 |
String(32) |
wxd678efh567hg6787 |
微信支付分配的公众账号ID(企业号corpid即为此appId) |
商户号 |
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会员充值 |
商品简单描述,该字段请按照规范传递,具体请见参数规定 |
商户订单号 |
out_trade_no |
是 |
String(32) |
20150806125346 |
商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一。详见商户订单号 |
标价金额 |
total_fee |
是 |
Int |
88 |
订单总金额,单位为分,详见支付金额 |
终端IP |
spbill_create_ip |
是 |
String(16) |
123.12.12.123 |
APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。 |
通知地址 |
notify_url |
是 |
String(256) |
http://www.weixin.qq.com/wxpay/pay.php |
异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 |
交易类型 |
trade_type |
是 |
String(16) |
JSAPI |
JSAPI 公众号支付NATIVE 扫码支付APP APP支付说明详见参数规定 |
商品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】。企业号请使用【企业号OAuth2.0接口】获取企业号内成员userid,再调用【企业号userid转openid接口】进行转换 |
举例如下:
<xml> <appid>wx2421b1c4370ec43b</appid> <attach>支付测试</attach> <body>JSAPI支付测试</body> <mch_id>10000100</mch_id> <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail> <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str> <notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url> <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid> <out_trade_no>1415659990</out_trade_no> <spbill_create_ip>14.23.150.211</spbill_create_ip> <total_fee>1</total_fee> <trade_type>JSAPI</trade_type> <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml>
注:参数值用XML转义即可,CDATA标签用于说明数据不被XML解析器解析。
归纳
优点:一码支持两码,可能方便
缺点:微信支付链路太长,耗时极长,特别是access_token接口,特别是生成access_token,耗时可能会达到5s。