SpringCloudGateway读取requestBody,适用multipart/form-data和application/json
由于requestBody中的数据默认只能读取一次,如果在filter中读取后,那controller层就拿不到参数了,创建一个预处理Filter,把exchange和request都复制出来,把参数啥的放进去然后传递复制出来的exchange和request,后面执行的filter取的都是复制出来的request中的数据,controller层接收参数就不会有问题了。上面方法得出的数据示例为:{
·
由于requestBody中的数据默认只能读取一次,如果在filter中读取后,那controller层就拿不到参数了,创建一个预处理Filter,把exchange和request都复制出来,把参数啥的放进去然后传递复制出来的exchange和request,后面执行的filter取的都是复制出来的request中的数据,controller层接收参数就不会有问题了。预处理Filter代码如下:
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* 最先执行的filter
* 后面的filter可以取到requestBody数据,也不会影响controller层数据的接收
*/
@Order(Integer.MIN_VALUE)
@Component
public class PreHandleFilter implements GlobalFilter {
public static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (exchange.getRequest().getHeaders().getContentType() == null) {
return chain.filter(exchange);
} else {
return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
DataBufferUtils.retain(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, cachedFlux);
return chain.filter(exchange.mutate().request(mutatedRequest).build());
});
}
}
}
后面的Filter中取requestBody用下面的方法:
/**
* 从requestBody中取出json或者form-data数据
*/
private String getRequestBodyFormRequest(ServerHttpRequest request) {
Flux<DataBuffer> body = serverHttpRequest.getBody();
StringBuilder sb = new StringBuilder();
body.subscribe(buffer -> {
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
String bodyString = new String(bytes, StandardCharsets.UTF_8);
sb.append(bodyString);
});
return sb.toString();
}
取出来的json格式数据是正常的,直接解析用就可以。
但是form-data数据是浏览器发起请求的所有数据,示例如下:
----------------------------656104841052683944615106
Content-Disposition: form-data; name="name"
jason.zheng
----------------------------656104841052683944615106
Content-Disposition: form-data; name="addr"
jinan
----------------------------656104841052683944615106--
所以,需要解析上面的参数名和参数值。方法也写好了,直接拿去用吧:
/**
* 解析从requestBody中获取的form-data数据,转换为json格式
*/
private String handleFormData(String str, ServerHttpRequest request) {
String contentType = request.getHeaders().getContentType().toString();
String sep = "--" + contentType.replace("multipart/form-data;boundary=", "");
String[] strs = str.split("\r\n");
boolean bankRow = false;// 空行
boolean keyRow = true;// name=xxx行
boolean append = false;// 内容是否拼接换行符
Map<String, String> params = new LinkedHashMap<>();// 这里保证接收顺序,所以用linkedhashmap
String s = null, key = null;
StringBuffer sb = new StringBuffer();
for (int i = 1, len = strs.length - 1; i < len; i++) {
s = strs[i];
if (keyRow) {
key = s.replace("Content-Disposition: form-data; name=", "");
key = key.substring(1, key.length() - 1);
keyRow = false;
bankRow = true;
sb = new StringBuffer();
append = false;
continue;
}
if (sep.equals(s)) {
keyRow = true;
if (null != key) {
params.put(key, sb.toString());
}
append = false;
continue;
}
if (bankRow) {
bankRow = false;
append = false;
continue;
}
if (append) {
sb.append("\r\n");
}
sb.append(s);
append = true;
}
if (null != key) {
params.put(key, sb.toString());
}
return JSON.toJSONString(params);// 这里是alibaba的fastjson,需要引入依赖
}
上面方法得出的数据示例为:{"name":"jason.zheng","addr":"jinan"}
-----------------完!
更多推荐
已为社区贡献1条内容
所有评论(0)