版权声明:本文为博主原创文章,遵循 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。