{"name": "service.pay"}
導(dǎo)入模塊
import pay from '@service.pay' 或 const pay = require('@service.pay')
接口定義
pay.getProvider()
獲取服務(wù)提供商
參數(shù):
無(wú)
返回值:
字符串,服務(wù)提供商的代號(hào),如廠商的英文品牌名稱,若無(wú)此服務(wù)則返回空字符串
示例:
console.log(pay.getProvider())
pay.pay(object)
使用支付完成付款
參數(shù):
參數(shù)名 |
類型 |
必填 |
說(shuō)明 |
orderInfo |
Json |
是 |
訂單信息 |
success |
Function |
否 |
成功回調(diào) |
fail |
Funtion |
否 |
失敗回調(diào) |
complete |
Function |
否 |
執(zhí)行結(jié)束后的回調(diào) |
orderInfo支持的key:
參數(shù)名 |
類型 |
必填 |
說(shuō)明 |
cpOrderId |
String |
是 |
訂單號(hào),不超過(guò)100個(gè)字符,一般由服務(wù)端生成 |
productName |
String |
是 |
商品名稱,不超過(guò)40個(gè)字符 |
productDesc |
String |
是 |
商品描述,不超過(guò)120個(gè)字符 |
callBackUrl |
String |
是 |
回調(diào)鏈接 |
price |
String |
是 |
商品價(jià)格,以分為單位,最大值999999 |
appKey |
String |
是 |
快應(yīng)用的appkey(在開(kāi)放平臺(tái)獲取) |
appId |
String |
是 |
快應(yīng)用的appid(在開(kāi)放平臺(tái)獲?。? |
timestamp |
String |
是 |
時(shí)間戳 |
sign |
String |
是 |
簽名 |
attach |
String |
否 |
附加信息 |
簽名規(guī)則:
要求:出于安全性的考慮,簽名應(yīng)由服務(wù)端生成給到快應(yīng)用客戶端,再由客戶端調(diào)起支付。
簽名算法:
1)構(gòu)造源串
* 將支付參數(shù)中需要參與簽名的參數(shù)(參見(jiàn)下表),按參數(shù)名的ASCII碼的增序排序,若遇到相同首字母,則看第二個(gè)字母,以此類推。 拼接后的源串格式為a=xxxxxx&b=xxxxxxx&c=xxxxxxxxxxx...
* 參數(shù)表:
參數(shù)名 |
描述 |
appId |
應(yīng)用id |
cpOrderId |
訂單號(hào) |
callBackUrl |
回調(diào)地址 |
productName |
產(chǎn)品名稱 |
price |
產(chǎn)品價(jià)格 |
timestamp |
時(shí)間戳 |
2)生成簽名值
* 將源串使用RSA算法(SHA256WithRSA),用私鑰進(jìn)行簽名
* 將簽名后的字符數(shù)組經(jīng)過(guò)Base64編碼,生成簽名值
3)代碼示例
public class Example {
private static final Logger logger = LoggerFactory.getLogger(Example.class);
public static String getSignContent() {
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("appId", "123456");
treeMap.put("cpOrderId", "abcde");
treeMap.put("callBackUrl", "http://xxx.aa.bb");
treeMap.put("productName", "游戲點(diǎn)卡");
treeMap.put("price", String.valueOf(200));
treeMap.put("timestamp", "233123123131");
Set<String> keys = treeMap.keySet();
StringBuilder sb = new StringBuilder();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
sb.append(key).append("=").append(treeMap.get(key)).append("&");
}
String signContent = sb.toString().substring(0, sb.length() - 1);
return signContent;
}
public static String sign(String content, String privateKey) {
String charset = "utf-8";
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.base64Decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
return Base64.base64Encode(signed);
} catch (Exception e) {
logger.error("簽名出錯(cuò).", e);
}
return null;
}
public static void main(String[] args) {
String signContent = getSignContent();
String priKey = "abcdefghijk";
String sign = sign(signContent, priKey);
System.out.println(sign);
}
}
success返回值
參數(shù)名 |
類型 |
說(shuō)明 |
code |
Integer |
返回狀態(tài)碼 |
message |
String |
消息內(nèi)容 |
result |
String |
支付結(jié)果 |
fail返回值
參數(shù)名 |
類型 |
說(shuō)明 |
code |
Integer |
返回狀態(tài)碼 |
message |
String |
消息內(nèi)容 |
失敗code定義
返回碼 |
描述 |
200 |
參數(shù)不合法,在message字段中可拿到詳細(xì)信息 |
1002 |
訂單號(hào)重復(fù) |
1003 |
超過(guò)最大限額 |
10040 |
通知支付發(fā)起者支付app 需要安裝或者更新 |
1005 |
結(jié)果未知 |
1007 |
版本無(wú)更新 |
1010 |
支付失敗 |
1012 |
正在處理中 |
1100 |
未知錯(cuò)誤 |
1200 |
簽名錯(cuò)誤 |
1201 |
缺少參數(shù) |
5000 |
金額錯(cuò)誤 |
5001 |
系統(tǒng)錯(cuò)誤 |
5002 |
余額不足 |
5003 |
參數(shù)異常 |
5004 |
用戶不存在 |
5005 |
登錄鑒權(quán)失敗 |
5006 |
商戶訂單號(hào)重復(fù) |
5555 |
支付失敗 |
6001 |
換訂單失敗 |
6002 |
獲取Token失敗 |
6003 |
訂單號(hào)不匹配 |
代碼示例:
pay.pay({
orderInfo: {
'cpOrderId': 'your orderid',
'productName': 'iWatch',
'productDesc': '42mm',
'callBackUrl': 'your callback url',
'price': 1,
'appKey': 'your appkey',
'appId': 'your appid',
'timestamp': (new Date()).getTime(),
'sign': 'sign'
'attach': '',
}
success: function (data) {
console.log(`handling success: ${data.code}`)
},
fail: function (data, code) {
console.log(`handling fail, code = ${code}`)
}
})
用戶支付成功后,快應(yīng)用平臺(tái)會(huì)根據(jù)快應(yīng)用在調(diào)用支付接口時(shí)提供的回調(diào)地址進(jìn)行回調(diào)。
回調(diào)參數(shù):
服務(wù)端在回調(diào)時(shí),會(huì)傳遞以下參數(shù)給cp服務(wù)端,建議cp服務(wù)端對(duì)訂單的字段進(jìn)行校驗(yàn)。
字段名 |
字段描述 |
是否參與簽名 |
notifyId |
通知id |
Y |
partnerOrder |
訂單ID |
Y |
productName |
商品名稱 |
Y |
productDesc |
商品描述 |
Y |
price |
商品價(jià)格 |
Y |
count |
商品數(shù)量 |
Y |
attach |
附件 |
Y |
sign |
簽名,由平臺(tái)用私鑰簽名,cp服務(wù)端需要使用平臺(tái)給cp分配的公鑰進(jìn)行驗(yàn)簽 |
|
簽名算法:
1) 構(gòu)建源串:將支付參數(shù)中需要參與簽名的參數(shù),按參數(shù)名的ASCII碼的增序排序,若遇到相同首字母,則看第二個(gè)字母,以此類推。 拼接后的源串格式為a=xxx&b=xxx&c=xxx
2) 將源串使用RSA算法(SHA256WithRSA),用私鑰進(jìn)行簽名,將簽名后的字符數(shù)組經(jīng)過(guò)Base64編碼,生成簽名值。
3) 示例代碼:
/**
* 簽名
*/
public static String signForCallBackCp(String priKey) {
TreeMap<String, String> treeMap = new TreeMap<>();
treeMap.put("notifyId", "notifyId");
treeMap.put("partnerOrder", "partnerOrder");
treeMap.put("productName", "productName");
treeMap.put("productDesc", "productDesc");
treeMap.put("price", String.valueOf("100"));
treeMap.put("count",
String.valueOf(1));
treeMap.put("attach", "");
Set<String> keys = treeMap.keySet();
StringBuilder sb = new StringBuilder();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
sb.append(key).append("=").append(treeMap.get(key)).append("&");
}
String signContent = sb.toString().substring(0, sb.length() - 1);
String sign = RsaUtil.sign(signContent, priKey, "SHA256WithRSA");
logger.info(" signForCallBackCp source:{} sign:{}", signContent, sign);
return sign;
}
public static String sign(String content, String privateKey, String signAlgorithm) {
String charset = "utf-8";
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.base64Decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature.getInstance(signAlgorithm);
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
return Base64.base64Encode(signed);
} catch (Exception e) {
logger.error("簽名出錯(cuò).", e);
}
return null;
}
響應(yīng)結(jié)果:
1)cp服務(wù)端如果對(duì)回調(diào)響應(yīng)成功,需要返回“ok”字符串,如果處理失敗,請(qǐng)返回非“ok”字符串。
2)快應(yīng)用平臺(tái)如果接收到響應(yīng)結(jié)果為“ok”字符串,則認(rèn)為回調(diào)成功,這個(gè)支付流程結(jié)束。如果接收到的結(jié)果為非“ok”字符串或回調(diào)異常則會(huì)進(jìn)行重試,最大回調(diào)重試次數(shù)為28次。
更多建議: