前言: 本文属于学习笔记,首先感谢原作者:凤凰牌老熊,博客链接:http://blog.lixf.cn/
作者先明确了概念:
交易是生成订单;支付是对订单进行付款。
支付行为有多种:我们碰到的大部分都是单次支付,其次还有转账和退款。以常见的单次支付来说明流程。
先说大家比较熟悉的银行卡支付,它分为线上支付和线下支付两种形式。线下支付就是通常说的POS收单,这里不介绍这个内容。对线上支付,按照卡的类别,分为贷记卡支付,也叫motopay、ePOS,即信用卡支付;和借记卡支付。按照支付形态,又分为认证支付、网银支付、快捷支付几种形态。银行卡网银支付要求银行卡必须开通在线支付功能,而快捷支付并不需要开通在线支付功能。主要利用支付验证要素(卡号、密码、手机号、CVN2、CVV2等),结合安全认证(例如短信验证码),让持卡人完成互联网支付。
快捷支付和认证支付类似,不同点在于绑卡之后,有些银行接口会返回token,后续使用token来作为支付凭证,无需提供卡号信息,这样电商也不需要本地保留卡号了。目前主要是银联有提供token接口。
走一个具体的例子看看吧。比如用户在电商系统中买了200块钱的东西,然后通过浦发银行卡做结算,用的是快捷支付。这个过程是:
用户在交易界面上,提交订单到交易系统中; 交易系统确认订单无误后,请求支付系统进行结算。这是在交易系统做的,后面工作就进入支付系统。
用户被引导到收银台页面, 让用户确认交易金额,选择支付方式,调用支付系统接口。
支付系统接收到支付请求,验证请求的各个字段是否有问题,确认无误后,调用支付网关执行支付。
支付网关请求浦发银行的快捷支付接口执行支付。
支付网关接收到支付结果报文后,对结果报文做解析,获取结果,并将结果告知交易系统。这可以通过URL或者RPC调用来实现。
商城系统收到支付结果后,开始执行后续操作。如果是支付成功,则开始准备出库。这一步在交易系统中处理,这里不做介绍。
网银支付,和快捷相比,就在第4步,插入一个步骤,将用户导航到网银页面输入支付信息,后续步骤是一样的。在资金流上也是相同的。 而在第五步获取返回结果上,一般银行就直接同步返回,银联是分为同步和异步返回。同步告知操作成功或者失败,异步告知扣款成功或者失败。同步操作和异步操作都需要调用方提供一个回调的URL地址,银联会将参数附加在这个地址上。通过解析这些参数可以得到执行结果。异步操作一般有2-3秒的延迟,取决于网络,以及该交易处理的复杂度。
上一节说的是支付的信息流,那资金流应该是怎么走的? 在第三步,会触发资金流。资金从用户个人账户上转移到电商公司的账户。当然,银行也不是活雷锋,这一笔交易是要收手续费的。资金是实时到账的,手续费一般是按月结算。有按交易笔数计费的,但大部分还是按照交易金额来收费。
同行快捷支付是比较简单的场景,让我们来逐步增加难度。如果支付系统没有对接浦发银行,那对浦发卡,就得走其它支付方式:银联或者第三方支付。
先说银联快捷。银联提供的多种接入方式,常说的快捷支付,在银联文档中叫商户侧开通token接口。通过这个接口,可以实现同行和跨行资金结算。不管收款行是浦发还是其它行,都可以完成结算。对本地和用户来说,体验是一样的。而在银联侧,后台资金流处理却不一样。了解这个资金流,有助于在异常情况下,了解资金到底跑到哪里了。
如果收款行也是浦发银行,银联发报文给浦发,浦发使用内部系统完成两个账户间的转帐,即时完成。
如果收款行是他行,比如工行。银联发指令给浦发和工行,分别完成各自账户上资金余额的增减,对个人和电商来说,这笔资金算是落地了。但实际资金流并不是立即发生。银联会在半夜做清结算后处理这笔资金。这个过程就是金融机构之间的清结算了,一般不需要关注。
如果使用的是第三方支付,对用户来说,处理的流程和银联一样。但资金流会不一样。 第三方支付在浦发和工行一般都会有落地的托管资金。 发生交易后,一般来说不会产生跨行资金流动。用户在浦发行的钱会被结算到第三方支付在浦发行的托管账户,而在工行的钱,会由第三方支付在工行的账户打到客户账户上。 这就降低了跨行资金流动成本。
目前国内主要银行都提供快捷和直联的接口。对电商来说,要对接哪些银行是个需要考虑的问题。(参见支付渠道)
一般来说,大部分银行都提供直联和网银接口,但不需要直接对接所有银行。银联和第三方支付也提供直联接口,可以直接对接国内主要银行。也不是所有银行都被银联支持,这和银联签约的接口有关,需要在对接时咨询银联。从我们使用情况看, 浦发借记卡、邮储银行卡是不支持的。 另外 交行、平安(含原深发)、上海银行、浦发、北京银行,上述银行卡需通过 这个地址 开通银联在线支付业务。
大部分银行提供的银行卡支付接口,借记卡支付和贷记卡支付是不一样的。但也有几个好心的银行,可以用一套接口同时开通借记卡和贷记卡。点名赞一下这些银行: 宇宙第一大行工商银行和建设银行。作为国内最保守的软件团队,和银行对接时务必做好足够的准备。在商务谈判完成、拿到银行的接口文档后,需要考虑两个问题:专线问题、加密问题。
对接银行有一个逃避不了的问题,就是如何根据卡号判断发卡行?这就需要卡bin。 BIN号即银行标识代码的英文缩写。BIN由6位数字表示,出现在卡号的前6位,由国际标准化组织(ISO)分配给各从事跨行转接交换的银行卡组织。银行卡的卡号是标识发卡机构和持卡人信息的号码,由以下三部分组成:发卡行标识代码(BIN号)、发卡行自定义位、校验码。目前,国内的 银行卡 按照数字打头的不同分别归属于不同的银行卡组织,其中以BIN号“4”字打头的银行卡属于VISA卡组织,以“5”字打头的属于MASTERCARD卡组织,以“9”字和“62”、“60”打头的属于中国银联,而“62”、“60”打头的银联卡是符合国际标准的银联标准卡 ,可以在国外使用,这也是中国银联近几年来主要发行的银行卡片。 大部分银行卡号前6位即可确定发卡行和卡类型,但也有非标卡需要6-10位才可以判断出来。需要维护一个卡bin库.
发卡机构 | BIN 范围 | 卡号长度 | 验证方式 |
---|---|---|---|
美国运通国际股份有限公司 (America Express) |
340000~349999 370000~379999 |
15位 | LUHN |
银联 | 620000~629999 | 16-19位 | LUHN |
大莱信用卡有限公司 (Diners Club) |
300000-305999 300000-305999 309000-309999 360000-369999 380000-399999 |
14位 | LUHN |
大莱信用卡有限公司 (美国加拿大) |
540000-559999 | 16位 | LUHN |
日本JCB | 352800-358999 | 16位 | LUHN |
万事达卡 (MasterCard) |
510000-559999 222100-272000 |
16位 | LUHN |
维萨卡 Visa |
400000 - 499999 | 13,16,19位 | LUHN |
1.从卡号最后一位数字开始,逆向将奇数位(1、3、5…)相加。
2.从卡号最后一位数字开始,逆向将偶数位数字先乘以2,如果乘积结果为两位数,则将其减去9,再求和。
3.将奇数位总和加上偶数位总和,结果应该可以被10整除。
加卡的时候先做LUHN,可以排除一部分输错卡号的情况。但要注意,国内有些银行的卡号不符合上述各种规定。
***************************************规则比较简单,照着规则写实现验证了一下,代码如下******************************************************
package com.daojia.luhn;
public class LuhnTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(isLuhn("6214830122080566"));
}
public static boolean isLuhn(String cardno){
System.out.println("input num="+cardno);
if(null==cardno||cardno.equals(""))
{
return false;
}
//校验数字
int length = cardno.length();
int[] wei = new int[length];
int oddsum =0;
int evensum =0;
for(int i=0;i<length;i++)
{
//从后往前截取数字
wei[i]= Integer.valueOf(cardno.substring(length-i-1, length-i));
//数字下表从0开始,相对于规则奇数
if(i%2==0)
{
evensum = evensum+ wei[i];
}else{
//偶数规则:计算
int dounum = doublecount(wei[i]);
oddsum = oddsum+ dounum;
}
}
System.out.println("oddsum="+oddsum);
System.out.println("evensum="+evensum);
if ((oddsum + evensum) % 10 == 0)
{
return true;
}else{
return false;
}
}
public static int doublecount(int num)
{
int result = 0;
return result=(num*2>=10)?(num*2-9):num*2;
}
}
输出:
在加卡的时候先做LUHN,可以排除一部分输错卡号的情况。但要注意,国内有些银行的卡号不符合上述各种规定。
我理解这个应该在前段做js校验,校验有问题的提示不强求。
版本号:当前接口的版本号;
编码方式: 默认都是UTF-8,指传输的内容的编码方式;
签名和签名方法: 生成报文的签名。 不是所有的字段都需要放到签名中,文档中会说明哪些字段需要签名;
签名算法:生成签名的算法,RSA, RSA128, MD5等。
商户代码:在渠道侧注册的商户号。
商户订单号:即发送给渠道的订单号;
发送时间:该请求送出的时间。
账号和账号类型: 银行卡、存折、IC卡等支持的账号类型以及对应的账号;
卡的加密信息:如信用卡的CVN2,有效期等。
开户行信息:开户行所在地以及名称;大部分是不需要的。
身份证件类型和身份证号: 可以用于实名验证的证件,指 身份证、军官证、护照、回乡证、台胞证、警官证、士兵证等。不同银行可以支持的证件类型不一样,这也不是问题。大部分就是身份证了。
姓名:真实姓名,必须和身份证一致;
手机号:在所在银行注册的手机号。
银联直联绑卡和银行绑卡类似,但是得注意验证接口,仅验证卡号和姓名,不验证身份证号和手机号。这导致第5步无法正常进行。银联只有到第六步执行绑卡时才做身份验证。 所以在处理上,还需要做一些调整,来确保和银行的流程的一致。 一种处理方法是,对银联,在第五步就开始调用银联接口执行绑卡操作,但是在本地标记为预绑卡状态;商户侧发送短信验证码,验证通过后,才将状态设置为绑卡成功。
银联网银绑卡处理起来比较麻烦。用户在电商页面上输入卡号,然后被导航到银联页面上去完成绑卡操作,成功后,银联返回一个token作为签约号,用于支持后续操作。这问题就来了,用户可以在银联页面上绑定一个别人的卡,而电商侧是无法知道这个卡的情况的。所以这种方式尽量不要用。
这里有第三方公司对接实名认证接口,从我们对接后上线来看,存在个别的人员因为行政区划调整,公安三方库不存在,但是去派出所查查到的case。
需要注意的问题: