三方接口对接常见数据处理方式汇总

发布时间:2024年01月16日

  • 日常开发中,我们经常会对接各种各样的第三方平台,常常需要对接口接入的数据参数进行处理,比如验签,解密,数据转换,数据二次封装等情况,本文总结了一些常见的数据处理案例,基本满足日常所见的各种情况,以供学习。POST 一般用来向服务端提交数据,本文主要讨论 POST 请求数据的几种方式。

数据请求格式

application/json

  • Method只支持POST,客户端设置请求头参数:“Content-type: application/json”;
  • 方法参数可以对象构成:加@RequestBody 注解前缀,否则不能接收到;
  • 文件上传可以通过转换成base64参数;

接收

  • 使用Postman模拟发送
    在这里插入图片描述
  • 接收数据
 @PostMapping( "/outbound")
 public String createOutboundOrderApollo(@RequestBody OutboundCreateOrderDTO createOrderDTO) {
     return JSON.toJSONString(createOrderDTO);
 }
  • 如果需要在请求头中添加一些自己的数据,需要从HttpServletRequest中获取请求数据进行二次封装;
    在这里插入图片描述
  • 接收数据:
 @PostMapping( "/test")
 public CainiaoR test(HttpServletRequest request) {
 	// 二次封装request
 	 CustomRequestWrapper requestWrapper = new CustomRequestWrapper(request);
 	 
     return CainiaoR.success();
 }
  • 需要注意的是:Body请求的数据在InputStream中获取;

发送

try {
	String url = "推送消息url";
	// 请求参数json字符串,格式如:"{\"name\":\"张三\"}" ,可通过构建对象后再转换成json字符串:JSONObject.toJSONString(obj)
	String content = "请求参数json字符串";
	HttpHeaders requestHeaders = new HttpHeaders();
	requestHeaders.setContentType(MediaType.APPLICATION_JSON);
	requestHeaders.add("Content-Encoding", "UTF-8");
	HttpEntity<String> entity = new HttpEntity<>(content, requestHeaders);
	// 调用远程接口:httpClient   restTemplate  等都可以使用,具体看个人习惯。
	ResponseEntity response = restTemplate.postForEntity(url, entity, String.class);
	JSONObject jsonObject = JSONObject.parseObject(response.getBody().toString());
	if (jsonObject.containsKey("code") && jsonObject.getString("code").equals("SUCCESS")) {
	   log.info("推送成功");
	}
} catch (Exception e) {
	log.error(e.getMessage());
}

multipart/form-data

  • 只支持POST请求,客户端设置请求头参数:“Content-type: multipart/form-data”;
  • http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
  • 在向服务器发送大量的文本、包含非ASCII字符的文本或二进制数据时这种编码方式效率很低。特别在文件上载时,所使用的编码类型应当是“multipart/form-data”,它既可以发送文本数据,也支持二进制数据上载。所以,大数据传输时一般选择“multipart/form-data”。
  • 属性设置为multipart/form-data,并且有至少一个input的type属性为file时,浏览器提交这个form时会在请求头部的Content-Type中自动添加boundary属性。

在这里插入图片描述

接收

  • 使用Postman模拟发送
    在这里插入图片描述

  • 接收数据

// 当请求参数有上传文件,3个及以下请求参数;
@PostMapping("/test")
public void test(String name, String id, MultipartFile file){
    log.info("name:{}, id:{}, file: {}", name, id, file);
}
// 当请求参数有上传文件,3个以上请求参数,封装成请求对象,不能加@RequestBody注解;
@PostMapping("/test")
public void test(RequestDto reqDto){
    log.info("name:{}, id:{}, file: {}", reqDto.getName(), reqDto.getIdcard(), reqDto.getFile());
}

发送

  • 以post方式调用第三方接口,以form-data 形式 发送 MultipartFile 文件数据
try {
   // 需要发送的文件流
   MultipartFile multipartFile = null;
   String url = "推送消息url";
   //  getStreamAsString 见  InputStream 提取;
   String content = getStreamAsString(multipartFile.getInputStream());
   HttpHeaders requestHeaders = new HttpHeaders();
   requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
   requestHeaders.add("Content-Encoding", "UTF-8");
   HttpEntity<String> entity = new HttpEntity<>(content, requestHeaders);
   // 调用远程接口:httpClient   restTemplate  等都可以使用,具体看个人习惯。
   ResponseEntity response = restTemplate.postForEntity(url, entity, String.class);
   JSONObject jsonObject = JSONObject.parseObject(response.getBody().toString());
   if (jsonObject.containsKey("code") && jsonObject.getString("code").equals("SUCCESS")) {
       log.info("推送成功");
   }
} catch (Exception e) {
   log.error(e.getMessage());
}

application/x-www-form-urlencoded

  • 当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。

接收

  • 请求参数不含MultlpartFile类型时可同时支持 GET和POST;
  • 上传文件:只支持POST(包括MutipleFile和Base64字符串)
  • 方法参数可以对象构成:不能加@RequestBody注解,否则不能接收到
  • 使用Postman模拟发送
    在这里插入图片描述
@PostMapping( "/test")
public void test(String name, String id){
    log.info("name:{}, id:{}", name, id);
}
@PostMapping("/test")
public void test(RequestDto reqDto){
    log.info("name:{}, id:{}, file: {}", reqDto.getName(), reqDto.getIdcard(), reqDto.getFile());
}
  • 如果需要在请求头中添加一些自己的数据,需要从HttpServletRequest中获取请求数据进行二次封装; 需要注意的是:Body请求的数据在Parameter中获取;

发送

public void test() {
   try {
        // params 需要发送的数据
        Map<String, String> params = new HashMap<>();
        String url = "推送消息url";
        String content = buildQuery(params, "UTF-8");;
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        requestHeaders.add("Content-Encoding", "UTF-8");
        HttpEntity<String> entity = new HttpEntity<>(content, requestHeaders);
        // 调用远程接口:httpClient   restTemplate  等都可以使用,具体看个人习惯。
        ResponseEntity response = restTemplate.postForEntity(url, entity, String.class);
        JSONObject jsonObject = JSONObject.parseObject(response.getBody().toString());
        if (jsonObject.containsKey("code") && jsonObject.getString("code").equals("SUCCESS")) {
            log.info("推送成功");
        }
    } catch (Exception e) {
        log.error(e.getMessage());
    }
}

public static String buildQuery(Map<String, String> params, String charset) throws IOException {
    if (params == null || params.isEmpty()) {
        return null;
    }

    StringBuilder query = new StringBuilder();
    Set<Map.Entry<String, String>> entries = params.entrySet();
    boolean hasParam = false;

    for (Map.Entry<String, String> entry : entries) {
        String name = entry.getKey();
        String value = entry.getValue();
        // 忽略参数名或参数值为空的参数
        if (StringUtils.areNotEmpty(name, value)) {
            if (hasParam) {
                query.append("&");
            } else {
                hasParam = true;
            }

            query.append(name).append("=").append(URLEncoder.encode(value, charset));
        }
    }

    return query.toString();
}

text/xml

  • 该种方式主要用来提交XML格式的数据。

接收

  • InputStream就是Java标准库提供的最基本的输入流。HttpServletRequest中InputStream只能读取一次,如果想要二次读取就会报错。 因此需要能够重复读取 InputStream 的方法。
  • 使用Postman模拟发送
    在这里插入图片描述
private final byte[] body;
private String bodyString;

@SneakyThrows
private byte[] initInputStream(HttpServletRequest request) {
	//  getStreamAsString 见  InputStream 提取;
    this.bodyString = getStreamAsString(request.getInputStream());
    return bodyString.getBytes(StandardCharsets.UTF_8);
}

发送

  • 与其他格式一样,将数据转为String传输。

Request请求中各个数据载体获取方法

Header

  • 请求标头是一种 HTTP 标头,它可在 HTTP 请求中使用,其提供有关请求上下文的信息,以便服务器可以定制响应。请求头由key/value对组成,每行为一对,key和value之间通过冒号(:)分割。请求头的作用主要用于通知服务端有关于客户端的请求信息。
// 获取请求头信息
private static Map<String, String> initHeaders(HttpServletRequest request) {
      Map<String, String> headers = new HashMap<>();
      Enumeration<String> headerNames = request.getHeaderNames();
      while (headerNames.hasMoreElements()) {
          String headerName = headerNames.nextElement();
          String header = request.getHeader(headerName);
          headers.put(headerName, header);
      }
      return headers;
}

Parameter

  • 参数(parameter)是从客户端(浏览器)中由用户提供的,若是GET方法是从URL中提供的,若是POST方法是从请求体(request body)中提供的;
  • request.getParameter()取得是通过容器的实现来取得通过类似post、get等方式传入的数据。request.getParameter()方法传递的数据,会从web客户端传到web服务器端,代表HTTP请求数据。
// 获取
private Map<String, String[]> initParameters(HttpServletRequest request) {
    Map<String, String[]> parameterMap = new HashMap<>();
    Enumeration<String> parameterNames = request.getParameterNames();
    while (parameterNames.hasMoreElements()) {
        String paramName = parameterNames.nextElement();
        String[] parameterValues = request.getParameterValues(paramName);
        parameterMap.put(paramName, parameterValues);
    }
    return parameterMap;
}

InputStream

private static String getStreamAsString(InputStream stream) throws IOException {
    try {
        Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
        StringBuilder response = new StringBuilder();

        final char[] buff = new char[1024];
        int read = 0;
        while ((read = reader.read(buff)) > 0) {
            response.append(buff, 0, read);
        }

        return response.toString();
    } finally {
        if (stream != null) {
            stream.close();
        }
    }
}

Attribute

  • request.setAttribute()和getAttribute()只是在web容器内部流转,仅仅是请求处理阶段。
  • 属性(attribute)是服务器端的组件(JSP或者Servlet)利用requst.setAttribute()设置的
  • 属性(attribute)的值既可以读取亦可以修改,读取可以使用request.getAttribute(),设置可使用request.setAttribute();

二次封装HttpServletRequest参考


/**
* @Author: carroll
* @Date: 2023-12-22
* @Since: 1.0
 *
 * 自定义HttpServletRequest  实现参数重复读取,请求头写入,请求头获取等功能
 * 满足各种平台各种数据数据格式传输和租户信息配置
*/
public class CustomRequestWrapper extends HttpServletRequestWrapper {
    private final Map<String, String[]> params;//定义参数集合
    private Map<String, String> headerMap;

    private final RedisUtils redisUtils;


    //    将request 里面的东西 缓存到这个数组里面
    private final byte[] body;
    private String bodyString;

    public CustomRequestWrapper(HttpServletRequest request, RedisUtils redisUtils) {
        super(request);
        this.params = initParameters(request);
        this.headerMap = initHeaders(request);
        this.redisUtils = redisUtils;
        this.body = initInputStream(request);
        getRequestOpenid();
    }

    @SneakyThrows
    private byte[] initInputStream(HttpServletRequest request) {
        this.bodyString = getStreamAsString(request.getInputStream());
        return bodyString.getBytes(StandardCharsets.UTF_8);
    }

    private void getRequestOpenid() {
        String openid = "";
        //  可以获取外部推送各种接口请求头中的数据  然后将对应的货主等信息放到请求头中
        String partner_code = getParameter("partner_code");
        if (CharSequenceUtil.isNotBlank(partner_code)) {
            openid = partner_code;
        }
        Object obj = redisUtils.get(GlobalConstants.OPENID + openid);
        if (Objects.isNull(obj)) {
            throw new BizException("未获取到有效请求头数据");
        }
        QiMenOwnerCache ownerCache = JSONUtil.toBean(obj.toString(), QiMenOwnerCache.class);
        initOwnerInfo(String.valueOf(ownerCache.getTenantId()), String.valueOf(ownerCache.getWarehouseId()), String.valueOf(ownerCache.getOwnerId()));
    }

    private Map<String, String[]> initParameters(HttpServletRequest request) {
        Map<String, String[]> parameterMap = new HashMap<>();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            String[] parameterValues = request.getParameterValues(paramName);
            parameterMap.put(paramName, parameterValues);
        }
        return parameterMap;
    }

    public void initOwnerInfo(String tenantId,String warehouseId,String ownerId) {
        headerMap.put(SecurityConstants.TENANT_ID_HEADER, tenantId);
        headerMap.put(SecurityConstants.WAREHOUSE_ID_HEADER, warehouseId);
        headerMap.put(SecurityConstants.OWNER_ID_HEADER, ownerId);
    }

    private static Map<String, String> initHeaders(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String header = request.getHeader(headerName);
            headers.put(headerName, header);
        }
        return headers;
    }

    @Override
    public String getParameter(String name) {
        String[] vs = params.get(name);
        if (vs == null || vs.length < 1)
            return null;
        return vs[0];
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(params.keySet());
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] vs = params.get(name);
        if (vs == null || vs.length < 1)
            return new String[0];
        return vs;
    }

    @Override
    public String getHeader(String name) {
        return this.headerMap.getOrDefault(name, headerMap.get(name.toLowerCase()));
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        return Collections.enumeration(this.headerMap.keySet());
    }

    public String getBodyString() {
        return this.bodyString;
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream innerBAIS = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() {
                return innerBAIS.read();
            }
        };
    }


    private static String getStreamAsString(InputStream stream) throws IOException {
        try {
            Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
            StringBuilder response = new StringBuilder();

            final char[] buff = new char[1024];
            int read = 0;
            while ((read = reader.read(buff)) > 0) {
                response.append(buff, 0, read);
            }

            return response.toString();
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }


}

验签与加密

  • 后续补充…

你知道的越多,你不知道的越多。

文章来源:https://blog.csdn.net/qq_40722827/article/details/135498930
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。