3:开发指南

2021年11月16日

开发指南

一:请求协议说明:

调用流程说明

合作方调用配送开放平台API,需要按照以下步骤:
填充参数>生成签名>拼装HTTP请求>发起HTTP请求>得到HTTP响应>解析json

二:接口协议

规则 说明
测试环境请求地址 http://open.s.bingex.com
生产环境请求地址 https://open.ishansong.com
传输协议 http
参数格式 application/x-www-form-urlencoded
字符编码 utf-8
请求方式 POST

三:返回值规则

规则 说明
数据格式 application/json
字符编码 utf-8
数据结构 {"status": 状态码,"msg": 错误信息, "data": 数据}
状态码为200代表正常,其它代表不正常。

四:接口入参介绍

闪送开放平台接口参数分为系统参数和业务参数两种,其中系统参数每个接口均需传入,业务参数是否传入取决于具体接口。
1:系统参数:clientId,accessToken,timestamp,sign 
2:业务参数:data
请求闪送开放平台接口时,系统参数、业务参数均在body请求体中传入

闪送开放平台接口参数列表:

参数名称 参数类型 是否必传 参数描述
clientId String yes App Key(去账户中心->应用信息查看)
accessToken String yes 授权成功获取
timestamp String yes 毫秒级时间戳
data String(必须是json串) 根据具体业务接口传递 业务入参
sign String yes 签名

五:商户授权

商户授权请参考商户授权

六:接口签名

签名说明


1:为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,开放平台服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。

2:将所有参数按照字典顺序进行排序,排除值为空以及sign字段。

3:将参数按照(App_secret的值+accessToken+"accessToken的值"+"clientId”+App ID的值+"data”+data的值+"timestamp”+timestamp的值)顺序拼接,参数对应的值不存在,参数和值都不进行拼接,参数使用utf-8编码。

4: 将拼接好的字符串进行MD5加密(32位大写加密),得到的MD5加密值最后转为"大写"赋给sign作为请求的参数。

参考方法:
一:accessToken参数为空
appSecret:bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW
clientId=ss6DzHy9GvHB46Jgo
data={"refreshToken":"10cab61c-5bcf-43f9-a120-feee9a24683d"}
timestamp=1631862240982

拼接成的加密串为:bnRtI4HQQB3JsAAcL5kizXBmzQA3iurWclientIdss6DzHy9GvHB46Jgodata{"refreshToken":"10cab61c-5bcf-43f9-a120-feee9a24683d"}timestamp1631862240982
得到的MD5加密值(32位大写加密)为:6966F7A42902CFFB96C49CF496A9CFC6

二:data参数为空
appSecret:bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW
accessToken=70882965-5e51-463f-a746-7bcf1b3f1c34
clientId=ss6DzHy9GvHB46Jgo
timestamp=1631862240982


拼接成的加密串为:bnRtI4HQQB3JsAAcL5kizXBmzQA3iurWaccessToken70882965-5e51-463f-a746-7bcf1b3f1c34clientIdss6DzHy9GvHB46Jgotimestamp1631862240982
得到的MD5加密值(32位大写加密)为:955E0C0DDAF87B9D26E0171BEF65C0D8


三:data参数不为空
appSecret:qBfAr1fAAFRw2Jat4i4yUaqE3Nh3NSw0
accessToken=70882965-5e51-463f-a746-7bcf1b3f1c34
clientId=ss6DzHy9GvHB46Jgo
timestamp=1631862240982
data={"cityId":1101}

拼接成的加密串为:bnRtI4HQQB3JsAAcL5kizXBmzQA3iurWaccessToken70882965-5e51-463f-a746-7bcf1b3f1c34clientIdss6DzHy9GvHB46Jgodata{"cityId":1101}timestamp1631862240982
得到的MD5加密值(32位大写加密)为:sign:56F220DAFDACCD1827544D75EEDEC086

七:代码示例

1、引入类

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.message.BasicNameValuePair;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;

2、签名sign参数计算函数

    //把字节数组转换成大写md5
    public static String bytesToMD5(byte[] input) {
        String md5str = null;
        try {
            //创建一个提供信息摘要算法的对象,初始化为md5算法对象
            MessageDigest md = MessageDigest.getInstance("MD5");
            //计算后获得字节数组
            byte[] buff = md.digest(input);
            //把数组每一字节换成16进制连成md5字符串
            md5str = bytesToHex(buff);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5str.toUpperCase();
    }

   //把字节数组转成16进位制数
    public static String bytesToHex(byte[] bytes) {
        StringBuffer md5str = new StringBuffer();
        //把数组每一字节换成16进制连成md5字符串
        int digital;
        for (int i = 0; i < bytes.length; i++) {
            digital = bytes[i];
            if(digital < 0) {
                digital += 256;
            }
            if(digital < 16){
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString();
    }

3、post请求函数

public static String sendPost(String url, Map<String,Object> params) {
        String response = null;
        try {
            List<NameValuePair> pairs = null;
            if (params != null && !params.isEmpty()) {
                pairs = new ArrayList<NameValuePair>(params.size());
                for (String key : params.keySet()) {
                    pairs.add(new BasicNameValuePair(key, params.get(key).toString()));
                }
            }
            CloseableHttpClient httpClient = null;
            CloseableHttpResponse httpResponse = null;
            try {
                httpClient = HttpClients.createDefault();
                HttpPost httppost = new HttpPost(url);
                if (pairs != null && pairs.size() > 0) {
                    httppost.setEntity(new UrlEncodedFormEntity(pairs, "UTF-8"));
                }
                httpResponse = httpClient.execute(httppost);
                response = EntityUtils
                        .toString(httpResponse.getEntity());
                System.out.println(response);
            } finally {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (httpResponse != null) {
                    httpResponse.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }

4、accessToken参数为空请求接口的代码示例(RefreshToken刷新AccessToken接口为例

    public static void main(String[] args) {
        String appSecret = "bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW";
        String clientId = "ss6DzHy9GvHB46Jgo";
        String data = "{\"refreshToken\":\"10cab61c-5bcf-43f9-a120-feee9a24683d\"}";
        Long timestamp = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer(appSecret)
                .append("clientId").append(clientId)
                .append("data").append(data)
                .append("timestamp").append(timestamp);
        //计算签名
        String sign = bytesToMD5(sb.toString().getBytes());
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("clientId",clientId);
        map.put("data", data);
        map.put("timestamp",timestamp);
        map.put("sign",sign);
        //请求接口获取的结果
        String res = sendPost("http://open.s.bingex.com/openapi/oauth/refresh_token",map);
    }

5、data参数为空请求接口的代码示例(查询开通城市接口为例

      public static void main(String[] args) {
        String appSecret = "bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW";
        String clientId = "ss6DzHy9GvHB46Jgo";
        String accessToken = "70882965-5e51-463f-a746-7bcf1b3f1c34";
        Long timestamp = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer(appSecret)
                .append("accessToken").append(accessToken)
                .append("clientId").append(clientId)
                .append("timestamp").append(timestamp);
        //计算签名
        String sign = bytesToMD5(sb.toString().getBytes());
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("clientId",clientId);
        map.put("accessToken", accessToken);
        map.put("timestamp",timestamp);
        map.put("sign",sign);
        //请求接口获取的结果
        String res = sendPost("http://open.s.bingex.com/openapi/developer/v5/openCitiesLists",map);
    }

6、data参数不为空请求接口的代码示例(查询保单产品接口为例

    public static void main(String[] args) {
        String appSecret = "bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW";
        String accessToken = "70882965-5e51-463f-a746-7bcf1b3f1c34";
        String clientId = "ss6DzHy9GvHB46Jgo";
        String data = "{\"cityId\":1101}";
        Long timestamp = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer(appSecret)
                .append("accessToken").append(accessToken)
                .append("clientId").append(clientId)
                .append("data").append(data)
                .append("timestamp").append(timestamp);
        //计算签名
        String sign = bytesToMD5(sb.toString().getBytes());
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("accessToken", accessToken);
        map.put("clientId",clientId);
        map.put("data",data);
        map.put("timestamp",timestamp);
        map.put("sign",sign);
        //请求接口获取的结果
        String res = sendPost("http://open.s.bingex.com/openapi/developer/v5/insuranceProductsList",map);
    }

7、accessToken和data参数都为空请求接口的代码示例(上传图片接口为例

public static void main(String[] args) throws IOException {
        String appSecret = "bnRtI4HQQB3JsAAcL5kizXBmzQA3iurW";
        String clientId = "ss6DzHy9GvHB46Jgo";
        Long timestamp = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer(appSecret)
                .append("clientId").append(clientId)
                .append("timestamp").append(timestamp);
        //计算签名
        String sign = bytesToMD5(sb.toString().getBytes());
        //图片文件的路径
        File file = new File("/Users/Desktop/WX20211108-164848.png");
        FileItem fileItem = new DiskFileItem(
                "iss",
                Files.probeContentType(file.toPath()),
                false,
                file.getName(),
                (int) file.length(),
                file.getParentFile());
        IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
        MultipartFile cMultiFile = new CommonsMultipartFile(fileItem);
        System.out.println(cMultiFile.getOriginalFilename());
        String fileName = cMultiFile.getOriginalFilename();
        CloseableHttpClient client = HttpClients.createDefault();
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.addTextBody("sign", sign, ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), Charset.defaultCharset()));
        builder.addTextBody("clientId", clientId, ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), "utf-8"));
        builder.addTextBody("timestamp", "" + timestamp, ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), "utf-8"));
        builder.addBinaryBody("file", cMultiFile.getInputStream(), ContentType.MULTIPART_FORM_DATA, fileName);
        HttpEntity build = builder.build();
        HttpPost httpPost = new HttpPost("http://open.s.bingex.com/openapi/file/v5/fileUpload");
        httpPost.setEntity(build);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.execute(httpPost);
            String response = EntityUtils
                    .toString(httpResponse.getEntity());
            System.out.println(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
关键词: