|
|
@@ -4,15 +4,23 @@ 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.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
|
|
|
+import org.springframework.cloud.gateway.support.BodyInserterContext;
|
|
|
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.HttpHeaders;
|
|
|
+import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
|
+import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
|
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
|
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.web.reactive.function.BodyInserter;
|
|
|
+import org.springframework.web.reactive.function.BodyInserters;
|
|
|
+import org.springframework.web.reactive.function.server.HandlerStrategies;
|
|
|
+import org.springframework.web.reactive.function.server.ServerRequest;
|
|
|
import org.springframework.web.server.ServerWebExchange;
|
|
|
import reactor.core.publisher.Flux;
|
|
|
import reactor.core.publisher.Mono;
|
|
|
@@ -56,11 +64,76 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
|
|
header.set("x-request-id", requestId);
|
|
|
header.set("x-request-time", ""+requestTime);
|
|
|
};
|
|
|
-
|
|
|
exchange.getRequest().mutate().headers(headers).build();
|
|
|
+
|
|
|
// 获取响应体
|
|
|
ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange);
|
|
|
return chain.filter(exchange.mutate().response(decoratedResponse).build());
|
|
|
+ //return getRequestBody(exchange, chain);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取 request body
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2025-07-18 14:44:53
|
|
|
+ */
|
|
|
+ private Mono<Void> getRequestBody(ServerWebExchange exchange, GatewayFilterChain chain) {
|
|
|
+ ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
|
|
|
+ Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
|
|
|
+ .flatMap(body ->{
|
|
|
+ //gatewayLog.setRequestBody(body);
|
|
|
+ return Mono.just(body);
|
|
|
+ });
|
|
|
+
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.putAll(exchange.getRequest().getHeaders());
|
|
|
+ // the new content type will be computed by bodyInserter
|
|
|
+ // and then set in the request decorator
|
|
|
+ headers.remove(HttpHeaders.CONTENT_LENGTH);
|
|
|
+ CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
|
|
|
+
|
|
|
+ // 通过 BodyInserter 插入 body(支持修改body), 避免 request body 只能获取一次
|
|
|
+ BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
|
|
|
+ return bodyInserter.insert(outputMessage,new BodyInserterContext())
|
|
|
+ .then(Mono.defer(() -> {
|
|
|
+ // 重新封装请求
|
|
|
+ ServerHttpRequest decoratedRequest = requestDecorate(exchange, headers, outputMessage);
|
|
|
+
|
|
|
+ // 记录响应日志
|
|
|
+ ServerHttpResponseDecorator decoratedResponse = recordResponseLog(exchange);
|
|
|
+ return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build())
|
|
|
+ .then(Mono.fromRunnable(() -> {
|
|
|
+ // 打印日志
|
|
|
+ //writeAccessLog(gatewayLog);
|
|
|
+ }));
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ private ServerHttpRequestDecorator requestDecorate(ServerWebExchange exchange, HttpHeaders headers,
|
|
|
+ CachedBodyOutputMessage outputMessage) {
|
|
|
+ return new ServerHttpRequestDecorator(exchange.getRequest()) {
|
|
|
+ @Override
|
|
|
+ public HttpHeaders getHeaders() {
|
|
|
+ long contentLength = headers.getContentLength();
|
|
|
+ HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
+ httpHeaders.putAll(super.getHeaders());
|
|
|
+ if (contentLength > 0) {
|
|
|
+ httpHeaders.setContentLength(contentLength);
|
|
|
+ } else {
|
|
|
+ // TODO: this causes a 'HTTP/1.1 411 Length Required' // on
|
|
|
+ // httpbin.org
|
|
|
+ httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
|
|
+ }
|
|
|
+ return httpHeaders;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Flux<DataBuffer> getBody() {
|
|
|
+ return outputMessage.getBody();
|
|
|
+ }
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
/**
|