虽然网关只做转发,但是对于每个转发的请求,我们都希望能够在日志中打印出请求的信息,网上版本很多,踩了很多坑,目前没找到完美的解决方案,最后我这个应该是大成版。希望对大家有用。
/**
* @author chenzhangx
* @date 2021/11/30 15:09
@Component
public class AccessFilter extends AbstractFilter implements GlobalFilter, Ordered {
private static Logger logger = LoggerFactory.getLogger(AccessFilter.class.getSimpleName());
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return cacheRequestBody(exchange, (serverHttpRequest) -> {
// don't mutate and build if same request object
if (serverHttpRequest == exchange.getRequest()) {
return chain.filter(exchange);
return chain.filter(exchange.mutate().request(serverHttpRequest).build());
@Override
public int getOrder() {
return -4;
//---------------------------------------------- private ---------------------------------------------------------
private void logInfo(ServerHttpRequest request, String body) {
String uri = request.getPath().value();
String params = request.getQueryParams().toString();
String method = request.getMethodValue();
String ip = request.getRemoteAddress().toString();
String headers = request.getHeaders().entrySet()
.stream()
.map(entry -> entry.getKey() + ": [" + String.join(";", entry.getValue()) + "]")
.collect(Collectors.joining("\n"));
long accessDate = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
sb.append("\n==================================[API_CALL]==================================\n");
sb.append("uri : " + uri + "\n");
sb.append("method : " + method + "\n");
sb.append("ip : " + ip + "\n");
sb.append("params : " + params + "\n");
sb.append("body : " + body + "\n");
sb.append("accessDate : " + accessDate + "\n");
sb.append("headers : { \n" + headers + " }\n");
sb.append("==============================================================================\n");
logger.info(String.valueOf(sb));
private Mono<Void> cacheRequestBody(ServerWebExchange exchange, Function<ServerHttpRequest, Mono<Void>> function) {
ServerHttpResponse response = exchange.getResponse();
ServerHttpRequest request = exchange.getRequest();
NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();
// Join all the DataBuffers so we have a single DataBuffer for the body
return DataBufferUtils.join(exchange.getRequest().getBody())
.defaultIfEmpty(factory.wrap(new EmptyByteBuf(factory.getByteBufAllocator())))
.map((dataBuffer) -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
String bodyString = new String(bytes, StandardCharsets.UTF_8);
logInfo(request, bodyString);
// 这里下面的代码我原先没写,后续的转发直接失效,因为body数据被拿出来了
Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
DataBuffer buffer = exchange.getResponse().bufferFactory()
.wrap(bytes);
return Mono.just(buffer);
return (ServerHttpRequest) new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}).switchIfEmpty(Mono.just(exchange.getRequest())).flatMap(function);
}