今年接手一项目需要用到网银这块,接触有工行、建行等几家银行,工行网银开发在磕磕碰碰中终于结束了。现在写这个文章主要是记录下开发流程,便于以后翻阅。
一、工行b2c概述
以下简述处理流程:
1. 客户在商户网站浏览商品信息,签订订单;
2. 商户按照工行B2C支付1.0.0.11接口形成提交数据,并使用工行提供API和商户证书对订单数据签名,形成form表单返回客户浏览器,表单action地址指向工行接收商户订单信息的servlet;
3. 客户确认使用工行支付后,提交此表单到工行;
4. 工行网银系统接收此笔订单,对订单信息和商户信息进行检查;
5. 通过检查则显示工行支付页面,1.0.0.11版本会提示客户输入交易卡号;
6. 客户输入后提交;
7. 银行查询客户相关信息;
8. 返回客户在银行的预留信息;
9. 客户确认;
10. 返回交易确认页面;
11. 不同类型客户使用各自认证方式进行交易确认,支持静态支付密码、动态口令卡、证书签名;
12. 银行校验后进行支付处理;
13. 工行进行支付指令处理后,如果商户需要工行实时通知,则工行将处理结果使用http协议post方式将通知消息数据提交到商户网站(这个接收银行通知消息的商户端地址是随商户订单数据提交银行的merURL字段),商户返回取货地址或关闭这个银行与其建立的连接后,银行才显示交易结果页面给客户。(注意1、发送通知和显示结果页面是串行的,所以商户端接收银行通知处理时间太长可能导致客户等待超时,造成银行不能将交易结果页面显示给客户。2、此连接是银行服务器自动和商户进行的连接,商户返回也是直接返回给银行,商户端不能对银行的这个请求进行重定向。)
14. 工行进行支付指令处理后,如果商户不需要工行实时通知,则工行直接显示交易结果给客户。
二、“凡事预则立,不预则废”在了解工行b2c大概流程之后,来看两个接口:1、支付接口2、通知接口。
1、支付接口,交易数据整合到一个xml格式串,作为表单的一项整体提交,FORM表单数据如下:
变量名称 | 变量命名 | 长度定义 | 说明 |
接口名称 | interfaceName | MAX(30) | 必输, 取值:“ICBC_PERBANK_B2C” |
接口版本号 | interfaceVersion | MAX(15) | 必输, 取值:“1.0.0.11” |
交易数据 | tranData | 无限制 | 必输,签名; 整合所有交易数据形成的xml明文串,并做BASE64编码; 具体格式定义见下文; 注意: 需有xml头属性;整个字段使用BASE64编码; xml明文中没有回车换行和多余空格; |
订单签名数据 | merSignMsg | 无限制 | 必输, 商户使用工行提供的签名API和商户证书将tranData的xml明文串进行签名,得到二进制签名数据,然后进行BASE64编码后得到可视的merSignMsg; 注意:签名时是针对tranData的xml明文,不是将tranData进行BASE64编码后的串; |
商城证书公钥 | merCert | 无限制 | 必输, 商户用二进制方式读取证书公钥文件后,进行BASE64编码后产生的字符串; |
tranData数据具体格式定义参考(附件1)中的规则,需要注意的是:
通知类型:支付完成后,需要返回通知就用“HS”;不需要则用“AG”;这点自己在做的时候忽略了,导致接收返回参数时找原因比较痛苦,不提伤心事了。另一个就是:
返回商户URL:端口要用80或不指定,必须合法的URL,交易结束,将客户引导到商户的此url,即通过客户浏览器post交易结果信息到商户的此URL,接收到银行信息后处理写法如下(java):
String ResStr = "http://跳转到处理工行返回参数的地址";
getResponse().addHeader("HTTP/1.1 200", "OK");
getResponse().addHeader("Server", "Apache/1.39");
getResponse().setIntHeader("Content-Length",ResStr.length());
getResponse().addHeader("Content-type", "text/html");
getResponse().getWriter().write(ResStr);
getResponse().flushBuffer();
其他严格按照文档中规定的填写就可以了;
form表单如下:
<FORM action="https:/*****/servlet/NewB2cMerPayReqServlet" method="post" id="goBank" >
<INPUT NAME="interfaceName" TYPE="hidden" value="ICBC_PERBANK_B2C" ><br/>
<INPUT NAME="interfaceVersion" TYPE="hidden" value="1.0.0.11"><br/>
<INPUT NAME="tranData" TYPE="hidden" value="${rdate[0]}"><br/>
<INPUT NAME="merSignMsg" TYPE="hidden" value="${rdate[1]}"><br/>
<INPUT NAME="merCert" TYPE="hidden" value="${rdate[2]}"><br/>
</FORM>
这些数据定义完之后,根据工行提供的例子将交易数据,订单签名数据,商城证书公钥生成好传到前台from表单进行提交就ok了;
2、通知接口,表单定义如下:(具体参数定义参考附件1文档)
变量名称 | 变量命名 | 长度定义 | 说明 |
返回商户变量 | merVAR | 无限制 | 取值:商户提交接口中merVAR字段当返回银行结果时,作为一个隐藏域变量,商户可以用此变量维护session等等。由客户端浏览器支付完成后提交通知结果时是明文传输,建议商户对此变量使用额外安全防范措施,如签名、base64,银行端将此字段原样返回 |
通知结果数据 | notifyData | 无限制 | 银行通知消息,xml格式定义见下文,提交商户时对xml明文串进行了base64编码; xml串中没有回车换行和多余空格;包含xml头属性,且格式固定; |
银行对通知结果的签名数据 | signMsg | 无限制 | 银行使用自己证书对商户通知消息notifyData字段的xml格式明文串进行的签名,然后进行BASE64编码后的字符串。 注意:签名是对notifyData的xml明文进行签名,不是其BASE64编码后的串;签名后得到二进制数据,对此数据进行BASE64编码得到signMsg |
这里看到 merVAR 是原样返回的,所以就可以通过此变量进行自定义的验证等;通知结果数据,签名数据都是经过加密的,根据工行提供的解密方法进行解密,之后就能得到想要处理的数据了;
这里主要注意的是证书的选择,一般工行提供的证书是pfx格式,需要使用证书拆分工具将它拆成crt和key密钥在这里使用crt证书就可以;
原文地址:http://jiaxu.blog.51cto.com/1322870/1568706