洞察纵观鸿蒙next版本,如何凭借FinClip加强小程序的跨平台管理,确保企业在数字化转型中的高效运营和数据安全?
1065
2022-11-03
在SpringCloud gateway自定义全局过滤器中修改multipart/form-data类型请求体
关于SpringCloud gateway修改 “application/json” 类型的请求体的示例代码,网上的教程很全。但是对于修改 "multipart/form-data" 类型——既包含文件流信息又包含参数信息的请求体的示例代码并不是很多。本篇主要是根据本人工作碰到的问题来简单说明一下对于post请求发送的 "multipart/form-data" 类型请求体如何修改。因为本人技术有限,所以代码可能不优雅,如果有更好的修改办法,欢迎探讨。
首先我们需要认识到一点,就是无论是application/json类型的数据,还是multipart/form-data类型数据,还是以后可能存在的application/x-mutate() 方法生成一个新的实例。ServerWebExchange实例中持有的ServerHttpRequest实例的具体实现是ReactorServerHttpRequest;ReactorServerHttpRequest的父类AbstractServerHttpRequest中初始化内部属性headers的时候把请求的HTTP头部封装为只读的实例;所以, 不能直接从ServerHttpRequest实例中直接获取请求头HttpHeaders实例并且进行修改。不同content-type类型的body有着自己固定的格式要去,我们需要的就是在完成我们想要的修改后把body恢复到规定的格式,此外就是请求头中的Content-Length字段要刷新成我们修改后body的长度对于 post请求发送的"multipart/form-data" 类型的数据:请求头中的 Content-Type 是 multipart/form-data; 并且会随机生成 一个 boundary, 用于区分请求 body 中的各个数据; 每个数据以 --boundary 开始, 紧接着换行,下面是内容描述信息, 接着换2行, 接着是数据; 然后以 --boundary-- 结尾, 最后换行;示例报文格式如下:
POST HTTP/1.1Host: demo.comCache-Control: no-cachePostman-Token: 679d816d-8757-14fd-57f2-fbc2518dddd9Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="key"value------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="testKey"testValue------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="imgFile"; filename="no-file"Content-Type: application/octet-stream------WebKitFormBoundary7MA4YWxkTrZu0gW--
有了以上了解后,我们现在开始进行步骤的实施:
1. 读取request中的body信息
我们在读取body内容的时候需要先用到ServerWebExchange来进行ServerHttpRequest对象的获取。ServerWebExchange是一个HTTP请求-响应交互的契约。提供对HTTP请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。
ServerHttpRequest request = erverWebExchange.getRequest();
之后再使用ServerHttpRequest对象进行body信息读取,在这里我们是把读取到的字节流信息转为了String
exchange.getRequest().getBody().flatMap(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; String bodyString = null; try { bodyString = new String(bytes, "utf-8"); }catch (UnsupportedEncodingException e) { e.printStackTrace(); } log.info(bodyString);//打印请求参数 return Mono.just(bodyString);});
2. 对body信息进行修改
上一步我们已经可以获取到request中的body内容了,既然可以获取到内容,就说明我们可以对body进行修改后替换。
首先需要对获取到的String字符串进行解析,本人是根据content-type中的boundary字符传进行的分割解析:
String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9); String[] split = bodyString.split(boundary);
之后就可以根据解析到的信息进行自己想要的修改替换。修改替换完成后就可以按照报文格式进行body信息的拼接。示例拼接的工具类代码如下(此代码参考了hutool的代码信息),如果想要进一步优化,可以去看下相关的成熟的工具类信息,自己进行拼接。
import cn.hutool.core.io.IORuntimeException;import cn.hutool.core.io.resource.MultiResource;import cn.hutool.core.io.resource.Resource;import cn.hutool.core.util.ObjectUtil;import cn.hutool.core.util.StrUtil;import cn.hutool-.hutool.com.google.common.collect.Maps;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import java.util.Map;@Slf4jpublic class RequestAddParaUtils { private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n\r\n"; private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n"; private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary="; private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n\r\n"; /** * * @param contentType 请求类型 * @param bodyString 请求body信息 */ @SneakyThrows public static String addPara(String contentType, String bodyString) { StringBuffer stringBuffer = new StringBuffer(); String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);//获取随机字符传信息 String boundary_end = StrUtil.format("--{}--\r\n", boundary); Map
然后将组装好的finalStringData信息封装到Flux中。
Flux cachedFlux = Flux.defer(() -> Mono.just(exchange.getResponse().bufferFactory() .wrap(finalStringData.getBytes())));
3.重新组装request请求
我们修改好body的内容后,就可以进行request的重新组装了,这一步主要是更新Content-Length的信息和我们重新组装的body信息。
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator( exchange.getRequest()) { @Override public HttpHeaders getHeaders() { HttpHeaders = new HttpHeaders(); finalStringData.getBytes().length + ""); return } @Override public Flux getBody() { return cachedFlux; } };
4.代码归纳与说明
以上就是对于post请求发送的"multipart/form-data" 类型的数据进行修改的所有步骤,然后加上其他的细枝末节,总体代码信息如下
import cn.hutool.core.io.IORuntimeException;import cn.hutool.core.io.resource.MultiResource;import cn.hutool.core.io.resource.Resource;import cn.hutool.core.util.ObjectUtil;import cn.hutool.core.util.StrUtil;import cn.hutool.com.google.common.collect.Maps;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.core.io.buffer.*;import org.springframework.org.springframework.org.springframework.org.springframework.stereotype.Component;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Flux;import reactor.core.publisher.Mono;import java.util.Map;@Component@Slf4jpublic class WrapperRequestGlobalFilter implements GlobalFilter, Ordered {//, Ordered private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n\r\n"; private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n"; private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n\r\n"; @SneakyThrows @Override public Mono
5. 参考博文
(Spring Cloud Gateway-ServerWebExchange核心方法与请求或者响应内容的修改)报文详解)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~