spring cloud gateway如何正确获取请求体
- 文中spring cloud gateway版本为3.0.1
关于gateway如何获取请求体最近尝试了几种办法,虽然能获取到body,但是中途也遇到了一些问题。例如netty的内存溢出这种。虽然最后都解决了,但是还是想尝试更好的方案。终于在官方提供的包中发现了更好的。
首先定义一个全局的过滤器来缓存起来body、
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Slf4j
@Component
public class CacheBodyGlobalFilter implements Ordered, GatewayFilter, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return ServerWebExchangeUtils
.cacheRequestBody(
exchange,
(serverHttpRequest) -> chain.filter(
exchange.mutate().request(serverHttpRequest).build()));
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
然后提供一个工具类,在需要用到的地方直接调用就能获取到body了!
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.io.buffer.NettyDataBuffer;
import org.springframework.http.MediaType;
import org.springframework.web.server.ServerWebExchange;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
public class GatewayHttpUtil {
public static String getBodyContent(ServerWebExchange exchange) {
Object attribute = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
if (attribute == null || !(attribute instanceof NettyDataBuffer)) {
return null;
}
MediaType contentType = exchange.getRequest().getHeaders().getContentType();
if (contentType != null && contentType.toString().contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
return null;
}
NettyDataBuffer nettyDataBuffer = (NettyDataBuffer) attribute;
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(nettyDataBuffer.asByteBuffer());
return charBuffer.toString();
}
}
获取响应体
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Charsets;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
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.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.*;
/**
* 获取响应体
* @Author dong
* @Date 2023/11/7 下午 3:17
*/
@Slf4j
public class RespBodyLogFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
DataBufferFactory bufferFactory = response.bufferFactory();
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(response) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
// 获取响应 ContentType
String responseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
// 记录 JSON 格式数据的响应体
if (!StrUtil.isEmpty(responseContentType) && StrUtil.containsAny(responseContentType, MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE)) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
DataBufferUtils.release(join);
String responseData = new String(content, Charsets.UTF_8);
// 响应体
System.out.println(responseData);
return bufferFactory.wrap(content);
}));
}
}
return super.writeWith(body);
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
@Override
public int getOrder() {
return -1100;
}
}