必须先要吐槽一下,一个API连个好用的文档都没有,全靠和人当面沟通,浪费了一整天的时间调接口。
先上代码:
以下函数为API提供方提供的代码,大致就是把所有的参数全部打包起来和timestamp一起做一个SHA1加密。
public static String signatureWithParamsAndUrlPath(String urlPath, Map<String, Object> params, String secretKey,Long timestamp) throws Exception{
List<String> paramValueList = new ArrayList<String>();
if (params != null) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (entry.getValue() != null) {
paramValueList.add(entry.getKey() +"="+ entry.getValue());
}
}
}
Collections.sort(paramValueList);
StringBuilder valueToDigest = new StringBuilder();
valueToDigest.append(timestamp);
valueToDigest.append('\n');
valueToDigest.append(urlPath);
valueToDigest.append('\n');
for (int i = 0; i < paramValueList.size(); i++) {
if(i > 0){
valueToDigest.append("&");
}
valueToDigest.append(paramValueList.get(i));
}
String charset = "UTF-8";
return new String(Hex.encodeHex(
HmacUtils.hmacSha1(secretKey.getBytes(charset), valueToDigest.toString().getBytes(charset)), false));
}
好了,至此为止,API提供方没有提供其他的任何说明了:
问题是:
我的入参,形如device-a该以什么方式入参?没有说明。
如果我有多个入参,是否有变化?没有说明。
如果没有入参,返回值是什么。没有说明。
然后开始漫漫连调路。先写了一个大致如下的计算signature和形成header的方法
@Override
public List<Map> readAPI(Map<String, Object> inputparam) {
long time1 = System.currentTimeMillis();
String timestamp = String.valueOf(time1);
String signature = "";
List<BasicNameValuePair> content = new ArrayList<>();
for (String key : inputparam.keySet()) {
content.add(new BasicNameValuePair(key, inputparam.get(key).toString()));
}
try {
signature = this.signatureWithParamsAndUrlPath( this.path, inputparam ,this.key ,time1);
}
catch (Exception e)
{e.printStackTrace();}
List<BasicHeader> headers = new ArrayList<>();
headers.add(new BasicHeader("Id", this.id));
headers.add(new BasicHeader("Timestamp", timestamp));
headers.add(new BasicHeader("Signature", signature));
headers.add(new BasicHeader("content-type", "application/x-www-form-urlencoded"));
return requestAPI(headers, content);
}
并写了一个 HTTP API请求的方法(该方法已经是正确的方法了)
private List<Map> requestIpam(List<BasicHeader> headers,List<BasicNameValuePair> content ) {
HttpURLConnection connection = null;
BufferedReader reader = null;
String line = null;
List<Map> result = new ArrayList<>();
String json_read = "";
String content_read = "";
for (int i = 0; i < content.size(); i++) {
if(i > 0){
content_read += ("&");
}
content_read += (content.get(i));
}
try {
for (int i = 0; i <= 3; i++) {
URL url = new URL(this.host+this.path+"?"+content_read);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
for (BasicHeader header:headers){
connection.setRequestProperty(header.getName(),header.getValue());
}
connection.connect();// 建立TCP连接
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// 获取URLConnection对象对应的输出流
reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));// 发送http请求
// 循环读取流
while ((line = reader.readLine()) != null) {
json_read += line;// "\n"
}
logger.info("result"+json_read.toString());
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
return result;
}
然后说说是怎么一路被坑的吧:
首先:按API提供的同学的说法,需要把URLPATH拼到signature里面,好,我问拼的是
1.https://blog.csdn.net/guotch/article/details/95308055?not_checkout=1还是
2.blog.csdn.net/guotch/article/details/95308055?not_checkout=1还是
3.guotch/article/details/95308055?not_checkout=1
4.guotch/article/details/95308055
老哥一会一改口,一会是方案4,一会儿是方案1。
过了没多久又给我一个参考代码,一看,居然是方案5!
https://blog.csdn.net/guotch/article/details/95308055?params=[not_checkout=1]
然后开始改POST路径,我说老哥你这个not_checkout=1到底是怎么传进API的?
老哥说就是按content传。于是我写了一个out.write(param) 向OutputStreamWriter里面写,还是不对。
又是一顿改,老哥说你直接在url里面用问号拼起来就行。结果还是不行,终于无法忍受,当面找到老哥坐在一起调测
老哥一顿debug,哦给错了,其实前面那个signature是方案4。
终于花了一天的时间把API给调通了。
https://blog.csdn.net/java173842219/article/details/54020168