接口交互详解

请求参数

easyopen定义了7个固定的参数,用json接收

  1. {
  2. "name":"goods.get",
  3. "version":"2.0",
  4. "app_key":"test",
  5. "data":"%7B%22goods_name%22%3A%22iphone6%22%7D",
  6. "format":"json",
  7. "timestamp":"2018-01-16 17:02:02",
  8. "sign":"4CB446DF67DB3637500D4715298CE4A3"
  9. }
  • name:接口名称
  • version:接口版本号
  • app_key:分配给客户端的app_key
  • data:业务参数,json格式并且urlencode
  • format:返回格式,json,xml两种
  • timestamp:时间戳,yyyy-MM-dd HH:mm:ss
  • sign:签名串
    其中sign需要使用双方约定的签名算法来生成。

签名算法

签名算法描述如下:

  • 将请求参数按参数名升序排序;
  • 按请求参数名及参数值相互连接组成一个字符串:…;
  • 将应用密钥分别添加到以上请求参数串的头部和尾部:<请求参数字符串>
  • 对该字符串进行MD5运算,得到一个二进制数组;
  • 将该二进制数组转换为十六进制的字符串(全部大写),该字符串即是这些请求参数对应的签名;
  • 该签名值使用sign参数一起和其它请求参数一起发送给服务开放平台。
    伪代码:
  1. Map<String,Object> paramsMap = new ...; // 参数
  2. Set<String> keySet = paramsMap.keySet();
  3. List<String> paramNames = new ArrayList<String>(keySet);
  4. // 1.
  5. Collections.sort(paramNames);
  6. StringBuilder paramNameValue = new StringBuilder();
  7. // 2.
  8. for (String paramName : paramNames) {
  9. paramNameValue.append(paramName).append(paramsMap.get(paramName));
  10. }
  11. // 3.
  12. String source = secret + paramNameValue.toString() + secret;
  13. // 4.& 5.
  14. String sign = md5(source).toUpperCase();
  15. // 6.
  16. paramsMap.put("sign",sign);

请求方式

请求数据放在body体中,采用json格式。这里给出一个POST工具类:

  1. public class PostUtil {
  2. private static final String UTF8 = "UTF-8";
  3. private static final String CONTENT_TYPE_JSON = "application/json";
  4. private static final String ACCEPT_LANGUAGE = "Accept-Language";
  5. /**
  6. * POST请求
  7. * @param url
  8. * @param params
  9. * @param lang 语言zh,en
  10. * @return
  11. * @throws Exception
  12. */
  13. public static String post(String url, JSONObject params, String lang) throws Exception {
  14. String encode = UTF8;
  15. // 使用 POST 方式提交数据
  16. PostMethod method = new PostMethod(url);
  17. try {
  18. String requestBody = params.toJSONString();
  19. // 请求数据放在body体中,采用json格式
  20. method.setRequestEntity(new StringRequestEntity(requestBody, CONTENT_TYPE_JSON, encode));
  21. // 设置请求语言
  22. method.setRequestHeader(ACCEPT_LANGUAGE, lang);
  23. HttpClient client = new HttpClient();
  24. int state = client.executeMethod(method); // 返回的状态
  25. if (state != HttpStatus.SC_OK) {
  26. throw new Exception("HttpStatus is " + state);
  27. }
  28. String response = method.getResponseBodyAsString();
  29. return response; // response就是最后得到的结果
  30. } catch (Exception e) {
  31. throw e;
  32. } finally {
  33. method.releaseConnection();
  34. }
  35. }
  36. }
  • 请求操作代码:

    1. @Test
    2. public void testGet() throws Exception {
    3. Map<String, String> param = new HashMap<String, String>();
    4. Goods goods = new Goods();
    5. String data = JSON.toJSONString(goods);
    6. data = URLEncoder.encode(data, "UTF-8");
    7. param.put("name", "hello");
    8. param.put("app_key", appId);
    9. param.put("data", data);
    10. param.put("timestamp", getTime());
    11. param.put("version", "");
    12. param.put("format", "json");
    13. String sign = ApiUtil.buildSign(param, secret);
    14. param.put("sign", sign);
    15. System.out.println("请求内容:" + JSON.toJSONString(param));
    16. String resp = PostUtil.post(url, param,"zh");
    17. System.out.println(resp);
    18. }
    19. public String getTime() {
    20. return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    21. }

服务端验证

服务端拿到请求数据后会sign字段进行验证,验证步骤如下:

  • 根据客户端传过来的app_key拿到服务端保存的secret
  • 拿到secret后通过签名算法生成服务端的serverSign
  • 比较客户端sign和serverSign是否相等,如果相等则证明客户端传来的数据是合法数据,否则不通过返回错误信息。
  • 处理业务,返回结果