细数支付宝支付接入的种种
- 我只用过网页支付和手机版网页支付,APP 相关完全不懂
- 我具体只看过即时到帐相关的两个
- 我只具体看过 Java 的 SDK
BUG
-
http://club.alipay.com 点击登录,无法出现登陆框
- Safari OSX 10.9.4
本来打算去支付宝论坛发帖咨询的,结果特么的,需要版主审核身份……
都什么年代了,还用这样。
这小破论坛里面的提问也是不找边际,回答也是模棱两可。
要不是想贴个请求上去问问,我才不会去登录……
竟然还要审核,不知道现在审核过了没有。
- 使用 RSA 加密验证的时候要求提交公钥
- 登录、支付密码把控在财务手里,很多工程师是没有权利知晓的。
- 工程师只能生成 key,转码以后存为 txt 让财务上传。
- 不可预知才是是否多加了空格和回车(这点上支付宝竟然自己不愿意做校验和过滤,反而要求用户来做)
- 财务告诉我,同样一段,在 Chrome 下不行,IE 下就行。Win7 SP2。
首先确认上传的位置是否是RSA的下面,注意不要是DSA,无线目前不支持DSA加密;
另外请检查上传的格式中是否去除注释、空格、换行等,必须是一行的字符串 ,删除文件头“-----BEGIN PUBLIC KEY-----”与文件尾“-----END PUBLIC KEY-----”及空格、换行。
http://help.alipay.com/support/help_detail.htm?help_id=488520&sh=Y&tab=null&info_type=9
如果商家同时使用 无线网站支付 以及 网站支付,那将是噩梦一般的集成过程。
分别下载的 SDK,里面代码除了包名类名相同之外,其他基本都不同……
简单粗暴的合并方式就是把另外一边的代码直接复制到想同类里面,然后这个类就惨不忍睹了。
两套代码却共用相同一套配置:AlipayConfig
等
网站样例里面是:public static String sign_type = "MD5";
无线网站里面是:public static String sign_type = "0001";
0001 代表 RSA,而 MD5 就用 MD5,这常量定义得好诡异
以下这段代码,摘录自 无线支付的样例中
构造请求参数的时候做了如下判断,在非无线网站中却没有这段。
if(! sPara.get("service").equals("alipay.wap.trade.create.direct") && ! sPara.get("service").equals("alipay.wap.auth.authAndExecute")) {
sPara.put("sign_type", AlipayConfig.sign_type);
}
这段代码隐含一个意思:如果是 支付宝无线支付, sign_type
传出去的是 null
,但是你们文档里面 sign_type
是必填的。
做了下测试,如果把 sign_type
传值了,结果返回的是“签名验证失败”
呵呵……
下面这类代码满天飞……
if(AlipayConfig.sign_type.equals("MD5") ) {
//
}
if(AlipayConfig.sign_type.equals("0001") ){
//
}
这样的代码意味着,如果你使用了网站和无线网站支付,则你必须使用同一种签名方式,但是恰恰默认的签名方式是不同的……
别以为机智地加一个变量名自己控制好用哪个就没事了,人家只拿这个全局变量的……
我曾经这样干
AlipayConfig.sign_type == 'MD5'
AlipayConfig.sign_type_mobile == '0001'
构建请求参数的时候装模作样地传入 sign_type
sParaTempToken.put("sec_id", AlipayConfig.sign_type);
或者
sParaTempToken.put("sec_id", AlipayConfig.sign_type_mobile);
buildRequest
时候他偷偷通过上面那段来处理签名,索性你就全部隐藏掉好了,让我自以为自己很机智……
无线支付中调用 AlipaySubmit.getRequestToken
的地方会 throw exception。
如果签名获得 token 的 request 出错了,无法解析返回的 token,其实这段 token 变成了,告诉你错误原因的一个 HTML 页面……
至于如何改进参照下面那点。
某些返回 HTTP Status 不合理
“签名验证错误” 你返回一个 HTML 页面,HTTP Status Code 是 200,是不合理的。应该返回是什么,请参照《图解 HTTP》。
因为返回的是 200,造成上面那个 exception。
当然了在 HttpProtocolHandler
也完全没处理 status code。
总体来说无线流程比网站要好一些
无线做法是先请求 token,拿着 token 去做之后操作,而网站是没有这个流程的。
if (paraText.get("res_data") != null) {
String res_data = paraText.get("res_data");
if(AlipayConfig.sign_type.equals("0001")) {
res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
}
Document document = DocumentHelper.parseText(res_data);
request_token = document.selectSingleNode( "//direct_trade_create_res/request_token" ).getText();
}
这段代码是在我重写的时候非常纠结的一段,原本没注意当中那 0001
所以在测试的时候总是不过。看到这段,才看明白。这代码写得,额……
最后呢,放弃 RSA了,全部都是用的 MD5,就像你们客服回答我一样:RSA 不对?那改用 MD5 啊。
还有其他的一些,比如 ALIPAY_GATEWAY_NEW
这特么是函数的入参……
public static String buildRequest(String ALIPAY_GATEWAY_NEW, Map<String, String> sParaTemp, String strMethod, String strButtonName) {}
最后贴一个图,我明白做客服是很烦躁,但是,我觉得我的要求还是挺合理的。