在SpringMVC编程中要想在过滤器或者拦截器获取到请求体body,进行一些操作(比如进行验签),需要自定义RequestWrapper extends HttpServletRequestWrapper对Request进行包装,否则你在过滤器里面读取了请求body后,controller就获取不到body了,因为body是输入流,流只能读取一次。(我的例子程序)
在SpringCloud Gateway中,有同样的需求。由于Gateway底层用的Webflux响应式编程,所以获取请求体的写法和SpringMVC是不一样的。
提供一个全局过滤器
package com.edu.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
* 在Spring Cloud Gateway中,由于请求的 body 只能被读取一次,因此通常的做法是在第一个过滤器中将请求的 body 读取出来,
* 然后将 body 数据存储在 ServerWebExchange 的 attributes 中,这样其他的过滤器就可以从 attributes 中获取到 body 数据。
* <p>
* 首先,我们需要创建一个全局过滤器来读取 body 数据,并将其存储在 ServerWebExchange 的 attributes ,
* 然后,其他的过滤器就可以从 ServerWebExchange 的 attributes 中获取到 body 数据:
* String body = exchange.getAttribute("cachedRequestBody");
*
* @author
* @date 2023年12月07日 13:19
*/
@Slf4j
@Component
public class CacheBodyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
HttpMethod method = exchange.getRequest().getMethod();
log.info("============CacheBodyGlobalFilter==========method:{}",method.name());
if (method == HttpMethod.GET || method == HttpMethod.DELETE) {
return chain.filter(exchange);
}
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
String bodyString = new String(bytes, StandardCharsets.UTF_8);
log.info("[CacheBodyGlobalFilter]获取到请求体---------{}", bodyString);
exchange.getAttributes().put("cachedRequestBody", bodyString);
DataBufferUtils.release(dataBuffer);
return chain.filter(exchange);
});
}
@Override
public int getOrder() {
return -9999;
}
}
后面过滤器使用
String bodyJson = exchange.getAttribute("cachedRequestBody");