package com.insight.gateway.filter; import com.insight.gateway.common.dto.LogDto; import com.insight.utils.Json; import com.insight.utils.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.DataBufferUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; 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; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; /** * @author 宣炳刚 * @date 2017/10/06 * @remark 调试信息过滤器 */ @Component public class LogFilter implements GlobalFilter, Ordered { private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * 请求信息日志过滤器 * * @param exchange ServerWebExchange * @param chain GatewayFilterChain * @return Mono */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); HttpMethod method = request.getMethod(); RequestPath path = request.getPath(); String source = getIp(headers); if (source == null || source.isEmpty()) { source = request.getRemoteAddress().getAddress().getHostAddress(); } String requestId = Util.uuid(); String fingerprint = Util.md5(source + headers.getFirst("user-agent")); LogDto log = new LogDto(); log.setRequestId(requestId); log.setSource(source); log.setMethod(method.name()); log.setUrl(path.value()); log.setHeaders(headers.toSingleValueMap()); request.mutate().header("requestId", requestId).build(); request.mutate().header("fingerprint", fingerprint).build(); // 读取请求参数 MultiValueMap<String, String> params = request.getQueryParams(); log.setParams(params.isEmpty() ? null : params.toSingleValueMap()); // 如请求方法为GET或Body为空或Body不是Json,则打印日志后结束 long length = headers.getContentLength(); MediaType contentType = headers.getContentType(); if (length <= 0 || !contentType.equalsTypeAndSubtype(MediaType.APPLICATION_JSON)) { logger.info("请求参数: {}", log.toString()); return chain.filter(exchange); } return readBody(exchange, chain, log); } /** * 输出请求体 * * @param exchange ServerWebExchange * @param chain GatewayFilterChain * @param log 日志DTO * @return Mono */ private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain, LogDto log) { Flux<DataBuffer> dataBufferFlux = exchange.getRequest().getBody(); return DataBufferUtils.join(dataBufferFlux).flatMap(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); // 重新构造请求 ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) { @Override public Flux<DataBuffer> getBody() { return Flux.defer(() -> { DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes); DataBufferUtils.retain(buffer); return Mono.just(buffer); }); } }; ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build(); return ServerRequest.create(mutatedExchange, HandlerStrategies.withDefaults().messageReaders()).bodyToMono(String.class).doOnNext(body -> { if (Pattern.matches("^\\[.*]$", body)) { List<Object> list = Json.toList(body, Object.class); log.setBody(list == null ? body : list); } else if (Pattern.matches("^\\{.*}$", body)) { Map obj = Json.toMap(body); log.setBody(obj == null ? body : obj); } else { log.setBody(body); } logger.info("请求参数:{}", log.toString()); }).then(chain.filter(mutatedExchange)); }); } /** * 获取过滤器序号 * * @return 过滤器序号 */ @Override public int getOrder() { return 0; } /** * 获取客户端IP * * @param headers 请求头 * @return 客户端IP */ private String getIp(HttpHeaders headers) { if (headers.isEmpty()) { return null; } AtomicReference<String> ip = new AtomicReference<>(headers.getFirst("X-Real-IP")); if (ip.get() == null || ip.get().isEmpty()) { ip.set(headers.getFirst("X-Forwarded-For")); } if (ip.get() == null || ip.get().isEmpty()) { ip.set(headers.getFirst("Proxy-Client-IP")); } if (ip.get() == null || ip.get().isEmpty()) { ip.set(headers.getFirst("WL-Proxy-Client-IP")); } return ip.get(); } }