研究了几天支付宝接口的调用,期间遇到了很多的问题,直到现在都还没解决,首先列举下问题
1、问题:
支付宝进入扫码付款界面后,手机扫描二维码付款,有时候电脑界面没有反应
可能性分析:
在成功付款的单子里,我观察了一下付款成功地址会变化,并且这个地址变化首先调用的不是我的
return_url地址,而是支付宝自己反馈的某些地址,比如:出现支付成功,倒数五秒进入另一个地址的
页面,还有显示交易成功的交易,再之后才是调用return_url的地址,也就是说这期间会连续跳转三次
的地址,而我扫码支付成功后(为什么说支付成功,其一支付宝账单里显示支付成功,其二服务器端
的tomcat的日志里显示notify_url被调用了),页面连第一次跳转都未实现,所以,根据判断,很可能
是支付宝沙箱那边出现的问题。
2、问题:
notify_url必须要放在外网能够访问到的地方,即服务器上。有个疑问,之前这个地址我都是放在本地的,然后使用手机支付宝沙箱进行了支付,在tomcat日志中虽然没有看到它调用notify_url地址,但是在手机支付宝账单中显示支付成功。
解决:
return_url是你发送支付请求成功后,客户端就会进行响应的页面跳转,但是无法判断是否支付成功,是否支付成功需要notify_url中的trade_status参数进行判断。
本次使用的是支付宝提供的demo进行的测试学习,体验了五个功能,分别是支付,交易查询,退款,
退款查询,交易结束。其中我还进行了部分的修改。
demo中给我们提供了一个AlipayConfig类和几个jsp页面:
AlipayConfig类如下:
public class AlipayConfig {
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String app_id = "";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String merchant_private_key = "";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String alipay_public_key = "";
public static String notify_url = "http://193.112.64.192/alipay/notify_url";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url = "http://193.112.64.192/alipay/return_url";
// 签名方式
public static String sign_type = "RSA2";
// 字符编码格式
public static String charset = "utf-8";
// 支付宝网关
public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
// 支付宝网关
public static String log_path = "D:\\logger";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1、其中app_id可以在https://openhome.alipay.com/platform/appDaily.htm?tab=info 中的沙箱环境中去找自己的app_id
2、使用公钥和私钥生成器,生成对应的公钥和私钥,将公钥填入以上地址中的应用公钥中,验证的时候会提示你使用签名,他提供签名工具的生成工具,通过私钥生成,然后进行验证,注意以上代码中的alipay_public_key不是我们刚刚生成的公钥,而是我们公钥和签名传给对方,对方自己生成的一个支付宝公钥(第一天在这个地方卡了很久),然后将这个值复制粘贴到代码中
3、商品私钥就是之前通过公私钥生成器生成的私钥,直接复制粘贴
4、notify_url和return_url需要在外网可以正常访问的网址,也就是需要挂在服务器
return_url同步通知的介绍:
买家在支付成功后会看到一个支付宝交易提示成功的页面,该页面会停留几秒,然后会自动跳转回商户指定的同步通知页面(参数return_url)
该页面中获得参数的方式,需要使用GET方式获取,如request.QueryString("out_trade_no")、$_GET['out_trade_no'];
该方式仅仅在买家付款完成以后进行自动跳转,因此只会进行一次
该方式不是支付宝主动去调用商户页面,而是支付宝的程序利用页面自动跳转的函数,使用户的当前页面自动跳转;
基于(4)的原因,可在本机而不是只能在服务器上进行调试;
返回URL只有一分钟的有效期,超过一分钟该链接地址会失效,验证则会失败;
设置页面跳转同步通知页面(return_url)的路径时,不要在页面文件的后面再加上自定义参数。例如:
错误的写法:http://www.alipay.com/alipay/return_url.php?xx=11
正确的写法:http://www.alipay.com/alipay/return_url.php
notify_url异步通知的介绍:
必须保证服务器异步通知页面(notify_url)上无任何字符,如空格、HTML标签、开发系统自带抛出的异常提示信息等;
支付宝是用POST方式发送通知信息,因此该页面中获取参数的方式,如:
request.Form("out_trade_no")、$_POST['out_trade_no']。
支付宝主动发起通知,该方式才会被启用;
只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账中交易状态为“等待买家付款”的状态默认是不会发送通知的);
服务器间的交互,不像页面跳转同步通知可以在页面上显示出来,这种交互方式是不可见的;
第一次交易状态改变(即时到账中此时交易状态是交易完成)时,不仅页面跳转同步通知页面会启用,而且服务器异步通知页面也会收到支付宝发来的处理结果通知;
程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。
一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:2m,10m,10m,1h,2h,6h,15h);
程序执行完成后,该页面不能执行页面跳转。如果执行页面跳转,支付宝会收不到success字符,会被支付宝服务器判定为该页面程序运行出现异常,而重发处理结果通知;
cookies、session等在此页面会失效,即无法获取这些数据;
该方式的调试与运行必须在服务器上,即互联网上能访问;
该方式的作用主要防止订单丢失,即页面跳转同步通知没有处理订单更新,它则去处理;
通知ID(参数notify_id)只有一分钟有效期,超过一分钟该次通知会验证失败。一旦验证成功下次再验证就会失效。
总结:
notify_url是支付宝模拟post数据给你,只要状态改变就会post给你
return_url是跳转,用户付款后跳转到你的页面.只有第一次会通知你,以后不会了.
参考链接:https://www.cnblogs.com/xishuqingchun/p/4864452.html
接下里就是介绍代码实现:
首先是创建他提供的发送http请求的工具包AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
alipayClient封装公共请求参数,
AlipayTradePagePayRequest设置付款请求;
付款其中的方法biz_content封装业务请求参数
其中biz_content必填的参数有
out_trade_no//订单号
total_amount//金额
subject//商品名称
product_code//销售产品码,与支付宝签约的产品码名称。 注:目前仅支持FAST_INSTANT_TRADE_PAY
请求以json格式传递
例如:
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金额,必填
String total_amount = new String(request.getParameter("WIDtotal_amount").getBytes("ISO-8859-1"),"UTF-8");
//订单名称,必填
String subject = new String(request.getParameter("WIDsubject").getBytes("ISO-8859-1"),"UTF-8");
//商品描述,可空
String body = new String(request.getParameter("WIDbody").getBytes("ISO-8859-1"),"UTF-8");
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//若想给BizContent增加其他可选请求参数,以增加自定义超时时间参数timeout_express来举例说明
//alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
// + "\"total_amount\":\""+ total_amount +"\","
// + "\"subject\":\""+ subject +"\","
// + "\"body\":\""+ body +"\","
// + "\"timeout_express\":\"10m\","
// + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节
//请求
String result = alipayClient.pageExecute(alipayRequest).getBody();//调用sdk生成表单
//输出,注意输出格式,错误容易验签失败
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
out.println(result);
发送完该请求到支付宝后,对于PC网站支付的交易,在用户支付完成之后,支付宝会根据API中商户传入的return_url参数,通过GET请求的形式将部分支付结果参数通知到商户系统。
页面返回的业务参数只有订单号,交易号,金额和支付宝唯一用户号(select_id)
注意:也就是获取不到商品描述信息Body
交易查询的功能,我修改了一下demo中直接向支付宝发送请求来获取自己的数据,我是在return_url验签成功后,直接插入到数据库表格中,然后交易查询的时候,直接查询插入的数据
退款申请我额外做了个退款申请列表,当用户发起退款申请,不是直接就申请成功,他会修改商品的status属性,变更为“退款申请中”的状态,然后根据这个状态进行表数据的检索,汇成一张子表来显示退款申请用户的列表,然后商户可以选择确认或者取消退款
退款申请查询,当用户退款成功,在退款申请查询中能查询到相应的退款订单信息否则显示信息为空
交易结束,交易结束是发生在订单形成,却没有付款的情况下,这一功能我没有进行修改,直接是发送请求到支付宝,而后返回相应的信息。
网友评论