Java调用百度API出现{status:211,message:APP SN校验失败}

Java调用百度API出现{"status":211,"message":"APP SN校验失败"}

  • {"status":211,"message":"APP SN校验失败"}

{“status”:211,“message”:“APP SN校验失败”}

1、百度官方提供了C#、Java、python、php等版本的sn签名计算算法:
sn计算算法

2、本人在接入API接口过程中发现官方demo不太完善。以下是本人的Java代码:

package cn.maps.baidu.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;

public class SnCalUtil {

    public SnCalUtil() {
    }

    /**
     * 计算sn跟参数对出现顺序有关(参数对放入顺序必须跟请求中对应参数的出现顺序保持一致):
     * get请求请使用LinkedHashMap保存,该方法根据key的插入顺序排序;
     * post请使用TreeMap保存,该方法会自动将key按照字母a-z顺序排序。
     * 所以get请求可自定义参数顺序(sn参数必须在最后)发送请求,
     * 但是post请求必须按照字母a-z顺序填充body(sn参数必须在最后)。
     *
     * @param url       请求路径url
     * @param paramsMap 请求参数对
     * @param sk        ak对应sk秘钥
     * @return sn签名
     * @throws UnsupportedEncodingException
     */
    public String getSn(String url, Map<?, ?> paramsMap, String sk) throws UnsupportedEncodingException {
        String paramsStr = toQueryString(paramsMap);
        url = url.replaceFirst("http://api.map.baidu.com", "").trim();
        url = url.replaceFirst("http://yingyan.baidu.com", "").trim();
        System.out.println("************************Calculate Sn >>>>>url:" + url);
        //url在计算sn签名的时候,不管是get请求还是post请求,必须带?
        String wholeStr = url + paramsStr + sk;
        System.out.println("************************Calculate Sn >>>>>wholeStr:" + wholeStr);
        //对上面wholeStr再作utf8编码
        String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
        System.out.println("************************Calculate Sn >>>>>tempStr:" + tempStr);
        //调用下面的MD5方法得到最后的sn签名
        String sn = MD5(tempStr);
        System.out.println("************************Calculate Sn >>>>>Sn:" + sn);
        return sn;
    }

    /**
     * 对请求参数Map内所有value作utf8编码,拼接返回结果
     *
     * @param data 请求参数对
     * @return str 字符串
     * @throws UnsupportedEncodingException 异常
     */
    public String toQueryString(Map<?, ?> data) throws UnsupportedEncodingException {
        StringBuffer queryString = new StringBuffer();
        for (Entry<?, ?> pair : data.entrySet()) {
            queryString.append(pair.getKey()).append("=");
            String ss[] = String.valueOf(pair.getValue()).split(",");
            if (ss.length>1){
                for(String s:ss){
                    queryString.append(URLEncoder.encode(s, "UTF-8")).append(",");
                }
                queryString.deleteCharAt(queryString.length()-1);
                queryString.append("&");
            }else {
                queryString.append(URLEncoder.encode(String.valueOf(pair.getValue()), "UTF-8"));
                queryString.append("&");
            }
        }
        if (queryString.length() > 0) {
            queryString.deleteCharAt(queryString.length() - 1);
        }
        return queryString.toString();
    }

    /**
     * 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制
     *
     * @param str 要计算的字符串
     * @return sn
     */
    public String MD5(String str) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(str.getBytes());
            StringBuffer sb = new StringBuffer();
            for (byte b : array) {
                sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
            }
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException ignored) {
        }
        return null;
    }
}

注意:
(1)因为我是从配置文件中读取百度API接口的url,计算sn签名时候是从.com以后开始,所以我的代码有如下转换:

url = url.replaceFirst("http://api.map.baidu.com", "").trim();
url = url.replaceFirst("http://yingyan.baidu.com", "").trim();
##百度Web服务API-逆地理编码接口地址(GET请求)
maps.baidu.position.url=http://api.map.baidu.com/reverse_geocoding/v3/?

##百度鹰眼轨迹服务——终端管理类——entity的创建接口(POST请求)
maps.baidu.yingyan.terminals.entity.add.url=http://yingyan.baidu.com/api/v3/entity/add?

url在计算sn签名的时候,不管是get请求还是post请求,必须带?,否则会出现如题所示的{“status”:211,“message”:“APP SN校验失败”}

(2)官方提供的toQueryString(Map data)方法中做了修改,对“,”转义处理。

for (Entry<?, ?> pair : data.entrySet()) {
    queryString.append(pair.getKey()).append("=");
    String ss[] = String.valueOf(pair.getValue()).split(",");
    if (ss.length>1){
        for(String s:ss){
            queryString.append(URLEncoder.encode(s, "UTF-8")).append(",");
        }
        queryString.deleteCharAt(queryString.length()-1);
        queryString.append("&");
    }else {
        queryString.append(URLEncoder.encode(String.valueOf(pair.getValue()), "UTF-8"));
        queryString.append("&");
    }
}

或者在HttpClient发送get请求时候替换参数里的逗号为“%2C”也可以。

你可能感兴趣的:(杂谈)