OPPO开放平台快应用支付服务文档
一、客户端支付接口
接口声明
{"name": "service.pay"}
导入模块
import pay from '@service.pay' 或 const pay = require('@service.pay')
接口定义
pay.getProvider()
获取服务提供商
参数:
无
返回值:
字符串,服务提供商的代号,如厂商的英文品牌名称,若无此服务则返回空字符串
示例:
console.log(pay.getProvider())
pay.pay(object)
使用支付完成付款
参数:
参数名 |
类型 |
必填 |
说明 |
orderInfo |
Json |
是 |
订单信息 |
success |
Function |
否 |
成功回调 |
fail |
Funtion |
否 |
失败回调 |
complete |
Function |
否 |
执行结束后的回调 |
orderInfo支持的key:
参数名 |
类型 |
必填 |
说明 |
cpOrderId |
String |
是 |
订单号,不超过100个字符,一般由服务端生成 |
productName |
String |
是 |
商品名称,不超过40个字符 |
productDesc |
String |
是 |
商品描述,不超过120个字符 |
callBackUrl |
String |
是 |
回调链接 |
price |
String |
是 |
商品价格,以分为单位,最大值999999 |
appKey |
String |
是 |
快应用的appkey(在开放平台获取) |
appId |
String |
是 |
快应用的appid(在开放平台获取) |
timestamp |
String |
是 |
时间戳 |
sign |
String |
是 |
签名 |
attach |
String |
否 |
附加信息 |
签名规则:
要求:出于安全性的考虑,签名应由服务端生成给到快应用客户端,再由客户端调起支付。
签名算法:
1)构造源串
* 将支付参数中需要参与签名的参数(参见下表),按参数名的ASCII码的增序排序,若遇到相同首字母,则看第二个字母,以此类推。 拼接后的源串格式为a=xxxxxx&b=xxxxxxx&c=xxxxxxxxxxx...
* 参数表:
参数名 |
描述 |
appId |
应用id |
cpOrderId |
订单号 |
callBackUrl |
回调地址 |
productName |
产品名称 |
price |
产品价格 |
timestamp |
时间戳 |
2)生成签名值
* 将源串使用RSA算法(SHA256WithRSA),用私钥进行签名
* 将签名后的字符数组经过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", "游戏点卡");
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("签名出错.", 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返回值
参数名 |
类型 |
说明 |
code |
Integer |
返回状态码 |
message |
String |
消息内容 |
result |
String |
支付结果 |
fail返回值
参数名 |
类型 |
说明 |
code |
Integer |
返回状态码 |
message |
String |
消息内容 |
失败code定义
返回码 |
描述 |
200 |
参数不合法,在message字段中可拿到详细信息 |
1002 |
订单号重复 |
1003 |
超过最大限额 |
10040 |
通知支付发起者支付app 需要安装或者更新 |
1005 |
结果未知 |
1007 |
版本无更新 |
1010 |
支付失败 |
1012 |
正在处理中 |
1100 |
未知错误 |
1200 |
签名错误 |
1201 |
缺少参数 |
5000 |
金额错误 |
5001 |
系统错误 |
5002 |
余额不足 |
5003 |
参数异常 |
5004 |
用户不存在 |
5005 |
登录鉴权失败 |
5006 |
商户订单号重复 |
5555 |
支付失败 |
6001 |
换订单失败 |
6002 |
获取Token失败 |
6003 |
订单号不匹配 |
代码示例:
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}`)
}
})
二、支付成功服务端回调
用户支付成功后,快应用平台会根据快应用在调用支付接口时提供的回调地址进行回调。
回调参数:
服务端在回调时,会传递以下参数给cp服务端,建议cp服务端对订单的字段进行校验。
字段名 |
字段描述 |
是否参与签名 |
notifyId |
通知id |
Y |
partnerOrder |
订单ID |
Y |
productName |
商品名称 |
Y |
productDesc |
商品描述 |
Y |
price |
商品价格 |
Y |
count |
商品数量 |
Y |
attach |
附件 |
Y |
sign |
签名,由平台用私钥签名,cp服务端需要使用平台给cp分配的公钥进行验签 |
|
签名算法:
1) 构建源串:将支付参数中需要参与签名的参数,按参数名的ASCII码的增序排序,若遇到相同首字母,则看第二个字母,以此类推。 拼接后的源串格式为a=xxx&b=xxx&c=xxx
2) 将源串使用RSA算法(SHA256WithRSA),用私钥进行签名,将签名后的字符数组经过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("签名出错.", e);
}
return null;
}
响应结果:
1)cp服务端如果对回调响应成功,需要返回“ok”字符串,如果处理失败,请返回非“ok”字符串。
2)快应用平台如果接收到响应结果为“ok”字符串,则认为回调成功,这个支付流程结束。如果接收到的结果为非“ok”字符串或回调异常则会进行重试,最大回调重试次数为28次。
更多建议: