相关文章推荐
想发财的镜子  ·  微信支付 JSAPI ...·  3 周前    · 
心软的小虾米  ·  Flutter ...·  2 周前    · 
爱笑的蜡烛  ·  Python Qt ...·  1 年前    · 
干练的地瓜  ·  Rxjava2 ...·  1 年前    · 
坚强的煎饼  ·  flutter Cannot open ...·  1 年前    · 

业务场景: 需要接入顺丰快递的服务器,对用户订单快递进行查询、生成、取消等操作
这时我们需要去 顺丰快递对外开放API官网 查询相关资料,注册并请求权限、按照相关规则发送请求进行操作
新丰桥平台API接口规范文件
API接口列表在线文档

万事开头难,查看 文档

❓如何对请求顺丰API

分析结果:
我们是 CP,要请求 SF的 API要发送上面六个参数

用户注册成为 CP得到 partnerID ,传 serviceCode 来指定的调用的 API服务代码,按指定的加密方式得到 数字签名 ,再把 相关请求的报文、时间戳、UUID随机数 作为参数,请求结果。

📰请求报文分析

每个请求的报文有所不同
这里以 路由查询报文 来分析

"language" : "0" , "trackingType" : "1" , "trackingNumber" : [ "444003077898" , "441003077850" ] , "methodType" : "1"

按照相关格式填写业务中的需要查询的快递订单id进去,实现相关查询

🌰Demo实践

Demo 代码

目标1:PostMan发送路由查询请求

目标:使用 POSTMAN发送一个路由查询请求

✍︎填参准备

⚠注意设置请求头

☢︎最重要的数字签名

文档中有加密demo
修改后输出需要的参数

   public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        // 请求唯一号
        String requestID = UUID.randomUUID().toString().replace("-", "");
        //时间戳 取报文中的timestamp(调用接口时间戳)
        String timestamp = String.valueOf(System.currentTimeMillis());
        //客户校验码    使用顺丰分配的客户校验码
        String checkWord = "XXXXXXX";
        //业务报文  去报文中的msgData(业务数据报文)
        String msgData = "{\n\"language\": \"0\", \"trackingType\": \"1\", \"trackingNumber\": [\"444003077898\", \"441003077850\"], \"methodType\": \"1\" }";
        //将业务报文+时间戳+校验码组合成需加密的字符串(注意顺序)
        String toVerifyText = msgData+timestamp+checkWord;
        //因业务报文中可能包含加号、空格等特殊字符,需要urlEnCode处理
        toVerifyText = URLEncoder.encode(toVerifyText,"UTF-8");
        //进行Md5加密
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(toVerifyText.getBytes("UTF-8"));
        byte[] md = md5.digest();
        //通过BASE64生成数字签名
        String msgDigest = new String(new BASE64Encoder().encode(md));
        System.out.println("时间戳:"+timestamp);
        System.out.println("请求唯一号:"+requestID);
        System.out.println("加密后的数字签名:"+msgDigest);

运行得到相关参数:

再填入剩下的参数

目标2:Java请求路由查询 API

目标:用 Java实现 post请求路由查询
就是从使用PostMan发送请求到在 Java中使用 HTTP请求工具类,对服务器传参,发送请求

🧰添加HTTP请求工具类请求接口

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    public static String postSFAPI(String url, String xml, String verifyCode) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        List<NameValuePair> parameters = new ArrayList<>();
        parameters.add(new BasicNameValuePair("xml", xml));
        parameters.add(new BasicNameValuePair("verifyCode", verifyCode));
        HttpPost post = postForm(url, new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8));
        String body = "";
        body = invoke(httpClient, post);
        try {
            httpClient.close();
        } catch (IOException var9) {
            logger.error("HttpClientService post error", var9);
        return body;
    private static String invoke(CloseableHttpClient httpclient, HttpUriRequest httpost) {
        HttpResponse response = sendRequest(httpclient, httpost);
        String body = "";
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            body = parseResponse(response);
        return body;
    private static String parseResponse(HttpResponse response) {
        HttpEntity entity = response.getEntity();
        String body = "";
        try {
            if (entity != null) {
                body = EntityUtils.toString(entity);
        } catch (ParseException | IOException var4) {
            logger.error("HttpClientService paseResponse error", var4);
        return body;
    private static HttpResponse sendRequest(CloseableHttpClient httpclient, HttpUriRequest httpost) {
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpost);
        } catch (IOException var4) {
            logger.error("HttpClientService sendRequest error", var4);
        return response;
    private static HttpPost postForm(String url, StringEntity entity) {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(entity);
        return httpPost;
    public static String post(String url, Map<String, String> params) throws UnsupportedEncodingException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(5000).setConnectTimeout(5000).setSocketTimeout(60000).build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        List<NameValuePair> paramsList = new ArrayList<>();
        Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramsList, "UTF-8");
        httpPost.setEntity(urlEncodedFormEntity);
        String body = invoke(httpClient, httpPost);
        try {
            httpClient.close();
        } catch (IOException var9) {
            logger.error("HttpClientService post error", var9);
        return body;

调用工具类请求API

   Map<String,String> params = new HashMap<>();
        params.put("requestID",requestID);
        params.put("msgDigest",msgDigest);
        params.put("msgData",msgData);
        params.put("timestamp",timestamp);
        params.put("partnerID","xxxxxx");
        params.put("serviceCode","EXP_RECE_SEARCH_ROUTES");
        String result = null;
        try {
            result = HttpClientUtil.post("https://sfapi-sbox.sf-express.com/std/service", params);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        System.out.println(result);

目标3:举一反三

只改变请求的服务代码和请求的报表亦可成功访问对应的服务?

接入其他 API时,需要先申请权限

修改请求参数

  • serviceCode服务代码
  • msgData请求报表 建议抽取静态变量,方便修改
  • 下面试着请求下订单接口

        // 现在指定 API的服务名
        private static String SERVICE_CODE = "EXP_RECE_CREATE_ORDER";
        // 请求报文
        private static String msgData = "{
        "cargoDetails":[
                "count":2.365,
    			"unit":"",
    			"weight":6.1,
    			"amount":100.5111,
                "currency":"HKD",
                "name":"护肤品1",           
                "sourceArea":"CHN"          
        "contactInfoList":	[
                "address":"广东省深圳市南山区软件产业基地11",
                "contact":"小曾",
                "contactType":1,
                "country":"CN",
                "postCode":"580058",
                "tel":"4006789888"
                "address":"广东省广州市白云区湖北大厦",
                "company":"顺丰速运",
                "contact":"小邱",
                "contactType":2,
                "country":"CN",
                "postCode":"580058",
                "tel":"18688806057"
        "language":"zh_CN",
        "orderId":"OrderNum20200612223"
    

    我们尝试了 使用 postman对路由查询 API发出请求,
    Java使用 HTTP工具类来接入路由查询 API,
    同时举一反三地接入了生成订单 API
    当然 Demo还可以进一步进行完善

    Demo 完善展望

  • 抽取服务代码做枚举类
  • 声明用户属性的常量
  • 分类:
    后端
    标签: