java 对接阿里云的【天眼数聚】全国快递物流查询-快递查询接口 笔记
介绍
【1】本文仅对简单认证和摘要签名认证方式做了记录(本质上对接不难,难在对于生成签名的字符串一个都不能错,反正我是觉得,干脆记录下来好了,天天看玄里玄乎的文档去猜想,怕不是有大病吧)
代码展示
QueryExpressUtil.java(自己编辑的快递查询工具类)
import cn.hutool.core.util.StrUtil; import com.jeequan.jeepay.core.exception.BizException; import io.netty.util.CharsetUtil; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import org.json.JSONObject; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.*; /** * 对接阿里快递查询接口的工具类(对应的三个参数需要自己去阿里云平台拿自己的补充上去) */ public class QueryExpressUtil { private static final String HOST = "https://express3.market.alicloudapi.com"; private static final String PATH = "/express3"; private static final String APPKEY = "xxxxx"; public static final String APPSECRET = "xxxxxxxxxxx"; public static final String APPCODE = "xxxxxxx"; //这部分属性是用于摘要签名认证方式的 public final static String HTTPMethod = "GET"; public final static String Accept = "application/json; charset=utf-8"; public final static String Content_MD5 = ""; public final static String Content_Type = "application/x-www-form-urlencoded; charset=UTF-8"; public final static String Date = ""; public final static String Headers = "X-Ca-Key:%s" +"\n"+ "X-Ca-Nonce:%s" +"\n"+ "X-Ca-Signature-Method:HmacSHA256" +"\n"+ "X-Ca-Timestamp:%s"; public static String PathAndParameters = ""; public static JSONObject QueryExpress(String number) throws Exception { return QueryExpress(number, null , null, true); } public static JSONObject QueryExpress(String number, String mobile , String type) throws Exception { return QueryExpress(number, mobile , type, true); } public static JSONObject QueryExpress(String number, String mobile , String type , boolean is_secret) throws Exception { if (is_secret) return getDataBySecret(number, mobile , type); return getDataByCODE(number, mobile , type); } /** * 由于这个函数是使用简单认证(AppCode)方式调用API * 通过APPCODE参数设置在请求头请求获得数据的,与APPKEY和APPSECRET无关。 * 但安全性有一定问题,务必使用HTTPS进行通信, * AppCode在传输过程中使用明文,而HTTP/WebSocket通信协议没有加密, * 一旦网络通信的网络包被抓取,有非常大的丢失AppCode的风险 * @param mobile 可选 * @param number 必填 * @param type 可选 */ public static JSONObject getDataByCODE(String number, String mobile , String type) throws Exception { if (number == null || number == "") throw new BizException("核心参数缺失"); Map<String, String> headers = new HashMap<String, String>(); //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 headers.put("Authorization", "APPCODE " + APPCODE); Map<String, String> querys = new HashMap<String, String>(); querys.put("number", number); querys.put("mobile", mobile); querys.put("type", type); HttpResponse response = HttpUtils.doGet(HOST, PATH, "GET", headers, querys); String json= EntityUtils.toString(response.getEntity()); JSONObject jsonObject = new JSONObject(json); return jsonObject; } /** * 这个是采用摘要签名认证方式做的请求 * @param number * @param mobile * @param type * @return * @throws Exception */ public static JSONObject getDataBySecret(String number, String mobile , String type) throws Exception { String uuid = UUID.randomUUID().toString(); long timestamp = System.currentTimeMillis(); //填充参数 Map<String, String> querys = new LinkedHashMap<String, String>(); //这个格式要写死,因为默认是升序的 querys.put("mobile", mobile); querys.put("number", number); querys.put("type", type); //生成签名 String sign = getSHA256StrJava(packageSignStr(uuid, querys,timestamp),APPSECRET); //请求头加入签名 Map<String, String> headers = new HashMap<String, String>(); headers.put("Accept", "application/json; charset=utf-8"); headers.put("Content-MD5", ""); headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); headers.put("Date", ""); headers.put("X-Ca-Key", APPKEY); headers.put("X-Ca-Nonce", uuid); headers.put("X-Ca-Signature-Method", "HmacSHA256"); headers.put("X-Ca-Timestamp", String.valueOf(timestamp)); headers.put("X-Ca-Signature-Headers", "X-Ca-Key,X-Ca-Nonce,X-Ca-Signature-Method,X-Ca-Timestamp"); headers.put("X-Ca-Signature", sign); HttpResponse response = HttpUtils.doGet(HOST, PATH, "GET", headers, querys); String json= EntityUtils.toString(response.getEntity()); JSONObject jsonObject = new JSONObject(json); return jsonObject; } /** * * 组装签名串 * @params uuid 随机数 * @params url 请求的阿里API * @params timestamp 时间戳 */ public static String packageSignStr(String uuid,Map<String,String> map,long timestamp){ String querys = ""; for (String key : map.keySet()) { if (map.get(key) != null && map.get(key) != "") { querys += key + "=" + map.get(key) + "&"; }else { querys += key + "&"; } } querys = querys.length() > 0 ? querys.substring(0,querys.length()-1) : ""; PathAndParameters = PATH+"?"+querys; String temp = HTTPMethod +"\n"+ Accept +"\n"+ Content_MD5 +"\n"+ Content_Type +"\n"+ Date +"\n"+ Headers +"\n"+ PathAndParameters; String res = String.format(temp,APPKEY, uuid, timestamp);return res; } /** * 生成加密签名 * @params content 组装好的签名串 * @params appSecret 密钥 * */ private static String getSHA256StrJava(String content, String appSecret) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(StrUtil.bytes(appSecret, CharsetUtil.UTF_8), "HmacSHA256"); mac.init(secret_key); byte[] binaryData = mac.doFinal(StrUtil.bytes(content, CharsetUtil.UTF_8)); return Base64.getEncoder().encodeToString(binaryData); } }
HttpUtils.java(阿里提供的http请求工具类,为了简单就拿来用了)
import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 阿里天眼聚合--全国快递物流查询--配套的http请求工具类 */ public class HttpUtils { /** * get * * @param host * @param path * @param method * @param headers * @param querys * @return * @throws Exception */ public static HttpResponse doGet(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception { HttpClient httpClient = wrapClient(host); HttpGet request = new HttpGet(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } return httpClient.execute(request); } /** * post form * * @param host * @param path * @param method * @param headers * @param querys * @param bodys * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, Map<String, String> bodys) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (bodys != null) { List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>(); for (String key : bodys.keySet()) { nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); } UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8"); formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); request.setEntity(formEntity); } return httpClient.execute(request); } /** * Post String * * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (StringUtils.isNotBlank(body)) { request.setEntity(new StringEntity(body, "utf-8")); } return httpClient.execute(request); } /** * Post stream * * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (body != null) { request.setEntity(new ByteArrayEntity(body)); } return httpClient.execute(request); } /** * Put String * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPut request = new HttpPut(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (StringUtils.isNotBlank(body)) { request.setEntity(new StringEntity(body, "utf-8")); } return httpClient.execute(request); } /** * Put stream * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPut request = new HttpPut(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (body != null) { request.setEntity(new ByteArrayEntity(body)); } return httpClient.execute(request); } /** * Delete * * @param host * @param path * @param method * @param headers * @param querys * @return * @throws Exception */ public static HttpResponse doDelete(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception { HttpClient httpClient = wrapClient(host); HttpDelete request = new HttpDelete(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } return httpClient.execute(request); } private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException { StringBuilder sbUrl = new StringBuilder(); sbUrl.append(host); if (!StringUtils.isBlank(path)) { sbUrl.append(path); } if (null != querys) { StringBuilder sbQuery = new StringBuilder(); for (Map.Entry<String, String> query : querys.entrySet()) { if (0 < sbQuery.length()) { sbQuery.append("&"); } if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) { sbQuery.append(query.getValue()); } if (!StringUtils.isBlank(query.getKey())) { sbQuery.append(query.getKey()); if (!StringUtils.isBlank(query.getValue())) { sbQuery.append("="); sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8")); } } } if (0 < sbQuery.length()) { sbUrl.append("?").append(sbQuery); } } return sbUrl.toString(); } private static HttpClient wrapClient(String host) { HttpClient httpClient = new DefaultHttpClient(); if (host.startsWith("https://")) { sslClient(httpClient); } return httpClient; } private static void sslClient(HttpClient httpClient) { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] xcs, String str) { } public void checkServerTrusted(X509Certificate[] xcs, String str) { } }; ctx.init(null, new TrustManager[] { tm }, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = httpClient.getConnectionManager(); SchemeRegistry registry = ccm.getSchemeRegistry(); registry.register(new Scheme("https", 443, ssf)); } catch (KeyManagementException ex) { throw new RuntimeException(ex); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } } }