修改经过Spring Gateway的表单中的Json数据

打印 上一主题 下一主题

主题 939|帖子 939|积分 2821

背景

使用Spring Cloud Gateway作为网关时有时候一个请求是既包含excel又包含json的表单数据,出于各种层面考虑网关需要获取并更新其中的json数据
依赖


  • Spring Boot版本:2.7.15
  • Hutool: 5.8.21
  • Java: 11
实现逻辑

实现分为2个部分

  • 使用上文提到的ModifyRequestBodyGatewayFilterFactory类来修改请求体,这样最后就不用我们手动包装
  • 核心service通过将表单转为String,然后根据其中的boundary进行分割,提取修改json报文部分后再进行组装
注意:示例代码的核心service处理的表单内容只是2个,Json数据的key指定为json,另一个excel文件流
自定义filter
  1. @Component
  2. @Slf4j
  3. public class RequestModifyFilter implements GlobalFilter, Ordered {
  4.     @Autowired
  5.     private ModifyRequestBodyGatewayFilterFactory modifyRequestBodyFilter;
  6.     @Autowired
  7.     private JsonRequestBodyRewriteService jsonRequestBodyRewriteService;
  8.     @Autowired
  9.     private FormDataRequestBodyRewriteService formDataRequestBodyRewriteService;
  10.     @Override
  11.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  12.         MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
  13.         if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) {
  14.             // 纯json报文处理逻辑
  15.             return modifyRequestBodyFilter
  16.                     .apply(
  17.                             new ModifyRequestBodyGatewayFilterFactory.Config()
  18.                                     .setRewriteFunction(byte[].class, byte[].class, jsonRequestBodyRewriteService))
  19.                     .filter(exchange, chain);
  20.         } else if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)) {
  21.             // form表单数据处理
  22.             return modifyRequestBodyFilter
  23.                     .apply(
  24.                             new ModifyRequestBodyGatewayFilterFactory.Config()
  25.                                     .setRewriteFunction(byte[].class, byte[].class, formDataRequestBodyRewriteService))
  26.                     .filter(exchange, chain);
  27.         } else {
  28.             return filter(exchange, chain);
  29.         }
  30.     }
  31.     @Override
  32.     public int getOrder() {
  33.         return OrderConstant.REQUEST_MODIFY_FILTER.getOrder();
  34.     }
  35. }
复制代码
核心service
  1. @Service
  2. @Slf4j
  3. public class FormDataRequestBodyRewriteService implements RewriteFunction<byte[], byte[]> {
  4.     private final String BOUNDARY_PREFIX_IN_CONTENT_TYPE = "----WebKitFormBoundary";
  5.     private final String BOUNDARY_PREFIX_IN_FORM_DATA = "------WebKitFormBoundary";
  6.     private final String BOUNDARY_SUFFIX = "--\r\n";
  7.     @Override
  8.     public Publisher<byte[]> apply(ServerWebExchange exchange, byte[] body) {
  9.         String finalResultString = "";
  10.         // 将表单转为字符串格式从而根据boundary分割表单数据。注意这里不能用默认编码
  11.         String request = StrUtil.str(body, StandardCharsets.ISO_8859_1);
  12.         // 获取boundary的随机字符信息
  13.         String contentType = exchange.getRequest().getHeaders().getContentType().toString();
  14.         String randomStr = contentType.substring(contentType.indexOf(BOUNDARY_PREFIX_IN_CONTENT_TYPE) + BOUNDARY_PREFIX_IN_CONTENT_TYPE.length());
  15.         // 这里和前端约定json数据的表单key为json
  16.         String keyPart = "^\r\nContent-Disposition: form-data; name="json"";
  17.         Pattern r = Pattern.compile(keyPart);
  18.         // 根据表单内分割线进行分割。并通过关键段落keyPart来找到目标json数据
  19.         String[] split = request.split(BOUNDARY_PREFIX_IN_FORM_DATA + randomStr);
  20.         for (int x = 0; x < split.length - 1; x++) {
  21.             Matcher m = r.matcher(split[x]);
  22.             if (m.find()) {
  23.                 // 找到了json报文部分数据
  24.                 String originalJsonString = split[x];
  25.                 // 找到 JSON 数据的起始和结束位置
  26.                 int startIndex = originalJsonString.indexOf("{"");
  27.                 int endIndex = originalJsonString.indexOf(""}") + 2;
  28.                 // 提取 JSON 数据
  29.                 String jsonData = originalJsonString.substring(startIndex, endIndex);
  30.                 log.info("原始报文为:{}", jsonData);
  31.                 JSONObject jsonObject = JSONUtil.parseObj(jsonData);
  32.                 jsonObject.set("empId", "2345");
  33.                 jsonObject.set("department", "Engineering");
  34.                 String modifiedString = originalJsonString.substring(0, startIndex) + jsonObject + originalJsonString.substring(endIndex);
  35.                 log.info("修改后报文为:{}", modifiedString);
  36.                 // 重新组装split数组
  37.                 finalResultString = finalResultString + modifiedString + BOUNDARY_PREFIX_IN_FORM_DATA + randomStr;
  38.             } else {
  39.                 // 重组表单数据
  40.                 finalResultString = finalResultString + split[x] + BOUNDARY_PREFIX_IN_FORM_DATA + randomStr;
  41.             }
  42.         }
  43.         // 补上最后一截数据
  44.         finalResultString = finalResultString + BOUNDARY_SUFFIX;
  45.         return Mono.just(finalResultString.getBytes(StandardCharsets.ISO_8859_1));
  46.     }
  47. }
复制代码
相关代码

https://github.com/eastcukt/demo-gatway
其他

核心service获取表单中的json数据逻辑挺复杂,根本原因是没有合适的方法进行对象转换,如果有像使用@RequestPart(value = "json")注解一样方便的方法将会非常方便也不用自己截取,各位大佬有更方便的方法感谢分享一下
参考

https://blog.csdn.net/qq_36966137/article/details/128536391

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王國慶

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表