ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Zuul网关之解析重组GET\POST\PUT请求并支持contentType=“multipart/form-data”

2021-01-02 18:32:38  阅读:562  来源: 互联网

标签:网关 Zuul String form JSONObject request 参数 context data


1、重组参数

  假设需要重新组装的参数如下:

@Setter
@Getter
public class DecodeParameters implements Serializable{

  private static final long serialVersionUID = -874947393093003083830L;

  // 通用参数
  private String channelNo;

  //业务参数
  private String data;

}

 

2、GET请求

  GET请求主要通过RequestContext参数requestQueryParams重置,设定解密之后的参数数值来实现参数重组,转发给后端微服务。

public void processRequestBody(DecodeParameters parameters){
RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); String method =request.getMethod().toUpperCase(); if(HttpMethod.GET.matches(method)){   Map<String,List<String>> requestQueryParam = context.getRequestQueryParams();     if(Objects.isNull(requestQueryParams)){    requestQueryParams = new HashMap<>();    }else{ requestQueryParams .remove("channelNo");    } //放置业务参数 if(StringUtils.isNotBlank(parameters.getData)){   JSONObject data = JSONObject.parseObject(paramters.getData());   for(String key : data.keySet()){    List<String> list = new ArrayList<String>(){     {       add(data.getString(key));     }   };   requestQueryParams.put(key,list);   } } //放置通用参数 List<String> list = new ArrayList<>(Arrays.asList(parameters.getChannelNo()));
requestQueryParams.put ("channelNo", list);   }
}

 

3、POST\PUT请求(contentType !=“multipart/form-data”)

  POST\PUT请求需要通过重写RequestContext的HttpServletRequestWrapper InputStream流实现参数重组。

  contentType =“application/json”这类这类场景的POST或者PUT请求,主要是通过重新设定InputStream流实现请求参数的重组,转发给后端。

public void processRequestBody(DecodeParameters parameters){
  RequestContext context = RequestContext.getCurrentContext();
  HttpServletRequest request = context.getRequest();
  String method =request.getMethod().toUpperCase();
  if(HttpMethod.POST.matches(method) || HttpMethod.PUT.matches(method)){
      JSONObject requestBodyObj= new JSONObject();
  requestBodyObj.put("channelNo", parameters.getChannelNo());
  //注意data先转化成json对象格式,后面同一转化成json字符串
  requestBodyObj.put("data", JSONObject.parseObject(parameters.getData()));
  String requestBody= JSONObject.toJSONString(requestBodyObj);
  byte[] reqBodyBytes =requestBody.getBytes();
  context.setRequest(new HttpServletRequestWrapper (context.getRequest()){
    @Override
    public ServletInputStream getInputStream() throws IOException{
      return new ServletInputStreamWrapper (reqBodyBytes);
    }

    @Override
    public int getContextLength(){
      return reqBodyBytes.length;
    }

    @Override
    public long getContentLengthLong(){
      return reqBodyBytes.length;
    });
    }
  }
}
 

 

4、POST\PUT请求(contentType =“multipart/form-data”) 

 contentType = “multipart/form-data”这类请求报文中,既有文本参数(data),又有文件参数(file),报文结构较为复杂。

在POST和PUT请求中主要通过重构multipart/form-data request 实现参数的重组,转发给后端。

public void processRequestBody(DecodeParameters param){
  RequestContext context = RequestContext.getCurrentContext();
  HttpServletRequest request = context.getRequest();
  String method =request.getMethod().toUpperCase();
  String contentType = request.getContentType();
  if(HttpMethod.POST.matches(method) || HttpMethod.PUT.matches(method)){
      if(StringUtils.isNotBlank(contextType) && contentType.toLowerCase().startsWith("multipart/form-data")){
      //重构multipart/form-data request
      MultipartEntityBuilder multiEntityBuilder = MultipartEntityBuilder.create()
      .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
      .setCharset(StandardCharsets.UTF_8)
      .setContentType(ContentType.create(multipart/form-data))
      //务必获取原始报文boudary数值并重新设置boudary
      .setBoundary(contentType.substring(contentType.indexOf("boundary+")+9))

      //数据包文本参数重组
      if(Objects.nonNull(param)){
      //规范业务参数格式
        String paramStr;
        if(StringUtils.isBlank(param.getData()) || !isJsonValidate(param.getData())){
          paramStr= JSONObject.toJSONString(param);
        }else{
          JSONObject dataObj = JSONObject.parseObject(param.getData());
          JSONObject paramObj = JSONObject.parseObject(JSONObject.toJSONString(param));
          paramObj.put("data", dataObj);
          paramStr = JSONObject.toJSONString(paramObj);
  }

  //重组
  ContentType dataContentType = ContentType.create("application/json",StandardCharsets.UTF_8);
  multiEntityBuilder.addTextBody("data",paramStr, dataContentType);
  //数据包文件参数重组
  MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
  MultipartHttpServletRequest multipartHttpServletRequest =resolver.resolveMultipart(request);
  buildBinaryBody(multiEntityBuilder,multipartHttpServletRequest);
  ByteArrayOutSteam byteArrayOutputStream();
  multiEntityBuilder.build().writeTo(byteArrayOutputStream);
  byte[] reqBodyBytes =byteArrayOutputSteam.toByteArray();
  context.setRequest(new HttpServletRequestWrapper (context.getRequest()){
    @Override
    public ServletInputStream getInputStream() throws IOException{
      return new ServletInputStreamWrapper (reqBodyBytes);
    }

    @Override
    public int getContextLength(){
      return reqBodyBytes.length;
    }

    @Override
    public long getContentLengthLong(){
      return reqBodyBytes.length;
    });
  }  
}

private boolean isJsonValidate(String str){
 try{
  JSON.parse(str);
  return true;
}catch (JSONException e){
  return false;
  }
}

private void buildBinaryBody(MultipartEntityBuilder multiEntityBuilder, MultipartHttpServletRequest multipartHttpServletRequest)thows IOException{
  MultiValueMap<String,MultipartFile> multiFiles = multipartHttpServletRequest.getMultiFileMap();
  for(String key : multiFiles.keySet()){
  List<MultipartFile> multipartFile = multiFiles.get(key);
  for(MultipartFile multipartFile : multipartFiles){
    String fileName = multipartFile.getOriginalFilename();
    multiEntityBuilder.addBinaryBody(key, multipartFile.getInputStream(), ContentType.DEFAULT_BINARY,fileName);
    }
  }
}

 

后续

  本文主要为了讲述如何实现Zuul对请求报文的参数重置修改,由于不方便拷贝源代码,采用纯文本手敲代码,难免会出现格式和魔数不规范,请读者忽视。

 

标签:网关,Zuul,String,form,JSONObject,request,参数,context,data
来源: https://www.cnblogs.com/gavincoder/p/14222970.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有