接口交互详解
请求参数
easyopen定义了7个固定的参数,用json接收
{
"name":"goods.get",
"version":"2.0",
"app_key":"test",
"data":"%7B%22goods_name%22%3A%22iphone6%22%7D",
"format":"json",
"timestamp":"2018-01-16 17:02:02",
"sign":"4CB446DF67DB3637500D4715298CE4A3"
}
- name:接口名称
- version:接口版本号
- app_key:分配给客户端的app_key
- data:业务参数,json格式并且urlencode
- format:返回格式,json,xml两种
- timestamp:时间戳,yyyy-MM-dd HH:mm:ss
- sign:签名串
其中sign需要使用双方约定的签名算法来生成。
签名算法
签名算法描述如下:
- 将请求参数按参数名升序排序;
- 按请求参数名及参数值相互连接组成一个字符串:
…; - 将应用密钥分别添加到以上请求参数串的头部和尾部:
<请求参数字符串> ; - 对该字符串进行MD5运算,得到一个二进制数组;
- 将该二进制数组转换为十六进制的字符串(全部大写),该字符串即是这些请求参数对应的签名;
- 该签名值使用sign参数一起和其它请求参数一起发送给服务开放平台。
伪代码:
Map<String,Object> paramsMap = new ...; // 参数
Set<String> keySet = paramsMap.keySet();
List<String> paramNames = new ArrayList<String>(keySet);
// 1.
Collections.sort(paramNames);
StringBuilder paramNameValue = new StringBuilder();
// 2.
for (String paramName : paramNames) {
paramNameValue.append(paramName).append(paramsMap.get(paramName));
}
// 3.
String source = secret + paramNameValue.toString() + secret;
// 4.& 5.
String sign = md5(source).toUpperCase();
// 6.
paramsMap.put("sign",sign);
请求方式
请求数据放在body体中,采用json格式。这里给出一个POST工具类:
public class PostUtil {
private static final String UTF8 = "UTF-8";
private static final String CONTENT_TYPE_JSON = "application/json";
private static final String ACCEPT_LANGUAGE = "Accept-Language";
/**
* POST请求
* @param url
* @param params
* @param lang 语言zh,en
* @return
* @throws Exception
*/
public static String post(String url, JSONObject params, String lang) throws Exception {
String encode = UTF8;
// 使用 POST 方式提交数据
PostMethod method = new PostMethod(url);
try {
String requestBody = params.toJSONString();
// 请求数据放在body体中,采用json格式
method.setRequestEntity(new StringRequestEntity(requestBody, CONTENT_TYPE_JSON, encode));
// 设置请求语言
method.setRequestHeader(ACCEPT_LANGUAGE, lang);
HttpClient client = new HttpClient();
int state = client.executeMethod(method); // 返回的状态
if (state != HttpStatus.SC_OK) {
throw new Exception("HttpStatus is " + state);
}
String response = method.getResponseBodyAsString();
return response; // response就是最后得到的结果
} catch (Exception e) {
throw e;
} finally {
method.releaseConnection();
}
}
}
请求操作代码:
@Test
public void testGet() throws Exception {
Map<String, String> param = new HashMap<String, String>();
Goods goods = new Goods();
String data = JSON.toJSONString(goods);
data = URLEncoder.encode(data, "UTF-8");
param.put("name", "hello");
param.put("app_key", appId);
param.put("data", data);
param.put("timestamp", getTime());
param.put("version", "");
param.put("format", "json");
String sign = ApiUtil.buildSign(param, secret);
param.put("sign", sign);
System.out.println("请求内容:" + JSON.toJSONString(param));
String resp = PostUtil.post(url, param,"zh");
System.out.println(resp);
}
public String getTime() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
服务端验证
服务端拿到请求数据后会sign字段进行验证,验证步骤如下:
- 根据客户端传过来的app_key拿到服务端保存的secret
- 拿到secret后通过签名算法生成服务端的serverSign
- 比较客户端sign和serverSign是否相等,如果相等则证明客户端传来的数据是合法数据,否则不通过返回错误信息。
- 处理业务,返回结果