# 接口说明
# 3.1 接口 URL
调用 API 的服务 URL 地址,目前提供了以下 2 个环境:
调用环境 | 服务URL |
---|---|
测试环境(双方人员联调使用) | 线下沟通 |
正式环境 | 线下沟通 |
# 3.2 数据交互规范
规则 | 说明 |
---|---|
传输方式 | HTTPS |
提交方式 | 采用POST |
数据格式 | 请求和返回数据格式都为JSON(context-type设置为application/json) |
签名算法 | SHA加密方式,参考签名规则 |
判断逻辑 | 先判断请求参数签名,后实现业务逻辑 |
字符编码 | UTF-8 |
# 3.3 合作方调宜信接口参数
# 3.3.1 公共请求参数
参数名称 | 类型 | 是否必传 | 说明 | 备注 |
---|---|---|---|---|
sysName | string | 是 | 调用方系统标识 | 宜信方提供 |
timeStamp | long | 是 | 系统时间 | 公共参数。单位:毫秒(System.currentTimeMillis()),长度:13 |
method | string | 是 | 方法名称 | 方法名称。决定具体调用的接口。 |
sign | string | 是 | SHA签名 | SHA签名,对请求参数中除sign字段的所有参数签名的结果。具体参考加3.4.2解密加验签demo |
# 3.3.2 响应参数
参数名称 | 类型 | 是否必须 | 说明 | 备注 |
---|---|---|---|---|
status | String | 是 | 返回状态码 | 1代表成功,其余均为失败,具体参考枚举 |
msg | String | 否 | 提示信息 | |
timestamp | long | 是 | 系统时间 | |
data | String | 否 | 成功返回商城订单号,失败返回null |
# 3.3.3 响应码枚举
code | desc |
---|---|
1 | 成功 |
1000 | 没有查到数据 |
1002 | 参数异常 |
1012 | 参数值不在处理的范围内 |
1017 | 商品太火爆,已经抢光啦 |
1019 | 您下单的商品售价已发生变化,请刷新页面查看最新价格。 |
1021 | 活动未开始或已结束 |
1025 | 此商品已超出限制,把机会留给别人吧 |
1032 | 太多人下单,请稍后再试试 |
1035 | 亲,还没有填写收货地址哦~ |
1036 | 亲,请再次核对收货地址哦~ |
1037 | 未填写充值手机号 |
1038 | 充值手机号格式不正确 |
1041 | 商品售价不能低于成本价 |
1042 | 商品每次只能购买1个哦 |
1043 | 达到库存上限啦~请修改购买数量 |
1050 | 预约商品尚未开始销售, 请稍等 |
0 | 失败,desc见msg |
# 3.4 加解密加验签工具
# 3.4.1 签名规则
- Step1:
对所有传入参数按照字段名的ASCII码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2...)拼接成字符strText 注意:为空的参数不参与签名(null不参与签名,空字符串参与签名)。
- Step2:
在第一步得到的str尾部拼接上&key=秘钥secretKey(宜信方提供)得到strSignTemp字符串,并对strSignTemp字符串进行SHA加密,得到sign值signValue
注意: 合作方的初始密钥,随机生成后,通过邮件发送给对方(因考虑邮件的安全性,上线后请及时更新密钥)。
# 3.4.2 参数加密DEMO(JAVA实现)
@Slf4j
public class HttpTest{
@Test
public void testHttp() throws Exception {
Map<String, String> paraMap = new HashMap<>();
//以下是业务参数(具体参考各接口请求参数列表)
paraMap.put("orgOrderId","m220427195913488954");
paraMap.put("uid","1234");
paraMap.put("channelId","channelId");
paraMap.put("orderType","0");
paraMap.put("actualAmount","12345.34");
paraMap.put("addressCode","12345");
paraMap.put("receiverPhone","13987655456");
paraMap.put("receiverAddress","收货地址");
//以下是公共参数(必传)
//时间戳
paraMap.put("timeStamp", String.valueOf(System.currentTimeMillis()));
//系统标识,宜信提供
paraMap.put("sysName","signDefaultSalt");
//请求接口名
paraMap.put("method","submitOrder");
//秘钥,宜信提供
String secretKey = "MZ7*AQ!@VHv&W7u%Jv6Ma2rUMwgASMqA";
//生成sign
String sign = sign(paraMap,secretKey);
paraMap.put("sign",sign);
//开始http访问
String res = httpClient("http://localhost:7006/order/third/submitOrder",paraMap);
log.info("res:{}",res);
}
/**
* 生成签名
* @param paraMap 参数
* @param secretKey 秘钥
* @return sign
* @throws Exception
*/
private String sign(Map<String, String> paraMap, String secretKey) throws Exception{
LinkedList<String> list = new LinkedList<String>();
for (Map.Entry<String, String> entry : paraMap.entrySet()) {
if (!key.equals(entry.getKey()) &&entry.getValue() != null && entry.getValue() != "") {
list.add(entry.getKey() + "=" + JSON.toJSONString(entry.getValue()) );
}
}
int size = list.size();
String[] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
String result = String.join("&",arrayToSort);
result+="&key="+secretKey;
String sign = SHA(result);
if(!paraMap.containsKey(key)){
paraMap.put(key,sign);
}
return sign;
}
/**
* 字符串 SHA 加密
*
* @param strText
* @return
*/
public static String SHA(String strText) throws Exception{
// 返回值
String strResult = null;
// 是否是有效字符串
if (strText != null && strText.length() > 0) {
// SHA 加密
// 创建加密对象 并傳入加密類型
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
// 传入要加密的字符串
messageDigest.update(strText.getBytes());
// 得到 byte 类型结果
byte byteBuffer[] = messageDigest.digest();
// byte to hex string
StringBuffer strHexString = new StringBuffer();
for (int i = 0; i < byteBuffer.length; i++) {
String hex = Integer.toHexString(0xff & byteBuffer[i]);
if (hex.length() == 1) {
strHexString.append('0');
}
strHexString.append(hex);
}
// 得到返回結果
strResult = strHexString.toString();
}
return strResult;
}
/**
* 发送HTTP请求
* @param urlStr
* @param paraMap
* @return
*/
public String httpClient(String urlStr, Map<String, String> paraMap) {
CloseableHttpResponse response = null;
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
httpClientConnectionManager.setMaxTotal(8);
httpClientConnectionManager.setDefaultMaxPerRoute(16);
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
CloseableHttpClient httpClient = httpClientBuilder.setConnectionManagerShared(true).build();
String resultString;
try {
log.info("httpClientProxy-开始-url:{},入参:{}",urlStr, paraMap);
HttpPost httpPost = new HttpPost(urlStr);
httpPost.setEntity(new StringEntity(JSON.toJSONString(paraMap)));
httpPost.setHeader("Content-type", "application/json");
response = httpClient.execute(httpPost);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("--响应头--");
Header[] headerArray = response.getAllHeaders();
for(Header header : headerArray) {
stringBuffer.append(header.getName()).append(": ").append(header.getValue()).append(",");
}
resultString = EntityUtils.toString(response.getEntity(),"UTF-8");
log.info("httpClientProxy-结束-url:{} ,httpPostConfig:{}, httpPostAllHeaders:{}, Http响应:{} ,入参:{} ,返回结果:{}",urlStr,httpPost.getConfig(),httpPost.getAllHeaders(), stringBuffer, paraMap,resultString);
return resultString;
} catch (Exception e) {
log.warn("httpClientProxy-异常-url:{} , 入参:{}",urlStr, paraMap,e);
throw new ApiException("httpClientProxy-异常");
} finally {
try {
if(response!=null){
response.close();
}
} catch (IOException e) {
log.warn("httpClientProxy-关闭资源异常-url:{} ,,入参:{}",urlStr, paraMap,e);
throw new ApiException("httpClientProxy-异常");
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
- 响应参数格式
```json
{
"status": "0",
"msg": "验签成功",
"timestamp": "1656656578233",
"data": "succ"
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8