update 优化 gateway filter顺序 与 代码工具封装
parent
92c941396a
commit
c8dfec28cc
|
|
@ -1,10 +1,10 @@
|
||||||
package com.ruoyi.gateway.filter;
|
package com.ruoyi.gateway.filter;
|
||||||
|
|
||||||
|
import com.ruoyi.gateway.utils.WebFluxUtils;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
@ -19,9 +19,8 @@ public class GlobalCacheRequestFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
// GET DELETE 不过滤
|
// 只缓存json类型请求
|
||||||
HttpMethod method = exchange.getRequest().getMethod();
|
if (!WebFluxUtils.isJsonRequest(exchange)) {
|
||||||
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) {
|
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> {
|
return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> {
|
||||||
|
|
@ -34,6 +33,6 @@ public class GlobalCacheRequestFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return 0;
|
return Ordered.HIGHEST_PRECEDENCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,19 @@ package com.ruoyi.gateway.filter;
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import com.ruoyi.common.core.utils.JsonUtils;
|
import com.ruoyi.common.core.utils.JsonUtils;
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
|
||||||
import com.ruoyi.gateway.config.properties.CustomGatewayProperties;
|
import com.ruoyi.gateway.config.properties.CustomGatewayProperties;
|
||||||
|
import com.ruoyi.gateway.utils.WebFluxUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
|
|
||||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局日志过滤器
|
* 全局日志过滤器
|
||||||
* <p>
|
* <p>
|
||||||
|
|
@ -43,16 +33,16 @@ public class GlobalLogFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
ServerHttpRequest request = exchange.getRequest();
|
|
||||||
String path = getOriginalRequestUrl(exchange);
|
|
||||||
String url = request.getMethod().name() + " " + path;
|
|
||||||
|
|
||||||
if (!customGatewayProperties.getRequestLog()) {
|
if (!customGatewayProperties.getRequestLog()) {
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
String path = WebFluxUtils.getOriginalRequestUrl(exchange);
|
||||||
|
String url = request.getMethod().name() + " " + path;
|
||||||
|
|
||||||
// 打印请求参数
|
// 打印请求参数
|
||||||
if (isJsonRequest(request)) {
|
if (WebFluxUtils.isJsonRequest(exchange)) {
|
||||||
String jsonParam = resolveBodyFromRequest(request);
|
String jsonParam = WebFluxUtils.resolveBodyFromCacheRequest(exchange);
|
||||||
log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
||||||
} else {
|
} else {
|
||||||
MultiValueMap<String, String> parameterMap = request.getQueryParams();
|
MultiValueMap<String, String> parameterMap = request.getQueryParams();
|
||||||
|
|
@ -79,38 +69,4 @@ public class GlobalLogFilter implements GlobalFilter, Ordered {
|
||||||
return Ordered.LOWEST_PRECEDENCE;
|
return Ordered.LOWEST_PRECEDENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断本次请求的数据类型是否为json
|
|
||||||
*
|
|
||||||
* @param request request
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
private boolean isJsonRequest(ServerHttpRequest request) {
|
|
||||||
MediaType contentType = request.getHeaders().getContentType();
|
|
||||||
if (contentType != null) {
|
|
||||||
return StringUtils.startsWithIgnoreCase(contentType.toString(), MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
|
|
||||||
//获取请求体
|
|
||||||
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
body.subscribe(buffer -> {
|
|
||||||
byte[] bytes = new byte[buffer.readableByteCount()];
|
|
||||||
buffer.read(bytes);
|
|
||||||
String bodyString = new String(bytes, StandardCharsets.UTF_8);
|
|
||||||
sb.append(bodyString);
|
|
||||||
});
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getOriginalRequestUrl(ServerWebExchange exchange) {
|
|
||||||
ServerHttpRequest request = exchange.getRequest();
|
|
||||||
LinkedHashSet<URI> uris = exchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
|
|
||||||
URI requestUri = uris.stream().findFirst().orElse(request.getURI());
|
|
||||||
return UriComponentsBuilder.fromPath(requestUri.getRawPath()).build().toUriString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,8 @@ import com.ruoyi.gateway.utils.WebFluxUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
|
||||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码过滤器
|
* 验证码过滤器
|
||||||
|
|
@ -49,7 +42,7 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String rspStr = resolveBodyFromRequest(request);
|
String rspStr = WebFluxUtils.resolveBodyFromCacheRequest(exchange);
|
||||||
Dict obj = JsonUtils.parseMap(rspStr);
|
Dict obj = JsonUtils.parseMap(rspStr);
|
||||||
validateCodeService.checkCaptcha(obj.getStr(CODE), obj.getStr(UUID));
|
validateCodeService.checkCaptcha(obj.getStr(CODE), obj.getStr(UUID));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -59,15 +52,4 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
|
|
||||||
// 获取请求体
|
|
||||||
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
|
||||||
AtomicReference<String> bodyRef = new AtomicReference<>();
|
|
||||||
body.subscribe(buffer -> {
|
|
||||||
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
|
||||||
DataBufferUtils.release(buffer);
|
|
||||||
bodyRef.set(charBuffer.toString());
|
|
||||||
});
|
|
||||||
return bodyRef.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.ruoyi.gateway.filter;
|
||||||
import cn.hutool.http.HtmlUtil;
|
import cn.hutool.http.HtmlUtil;
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
import com.ruoyi.gateway.config.properties.XssProperties;
|
import com.ruoyi.gateway.config.properties.XssProperties;
|
||||||
|
import com.ruoyi.gateway.utils.WebFluxUtils;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
|
@ -12,7 +13,6 @@ import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.buffer.*;
|
import org.springframework.core.io.buffer.*;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -43,7 +43,7 @@ public class XssFilter implements GlobalFilter, Ordered {
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
// 非json类型,不过滤
|
// 非json类型,不过滤
|
||||||
if (!isJsonRequest(exchange)) {
|
if (!WebFluxUtils.isJsonRequest(exchange)) {
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
// excludeUrls 不过滤
|
// excludeUrls 不过滤
|
||||||
|
|
@ -93,16 +93,6 @@ public class XssFilter implements GlobalFilter, Ordered {
|
||||||
return serverHttpRequestDecorator;
|
return serverHttpRequestDecorator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否是Json请求
|
|
||||||
*
|
|
||||||
* @param exchange HTTP请求
|
|
||||||
*/
|
|
||||||
public boolean isJsonRequest(ServerWebExchange exchange) {
|
|
||||||
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
|
||||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return -100;
|
return -100;
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,30 @@ package com.ruoyi.gateway.utils;
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.R;
|
import com.ruoyi.common.core.domain.R;
|
||||||
import com.ruoyi.common.core.utils.JsonUtils;
|
import com.ruoyi.common.core.utils.JsonUtils;
|
||||||
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
|
import com.ruoyi.gateway.filter.GlobalCacheRequestFilter;
|
||||||
|
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebFlux 工具类
|
* WebFlux 工具类
|
||||||
*
|
*
|
||||||
|
|
@ -16,6 +33,57 @@ import reactor.core.publisher.Mono;
|
||||||
*/
|
*/
|
||||||
public class WebFluxUtils {
|
public class WebFluxUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取原请求路径
|
||||||
|
*/
|
||||||
|
public static String getOriginalRequestUrl(ServerWebExchange exchange) {
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
LinkedHashSet<URI> uris = exchange.getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
|
||||||
|
URI requestUri = uris.stream().findFirst().orElse(request.getURI());
|
||||||
|
return UriComponentsBuilder.fromPath(requestUri.getRawPath()).build().toUriString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是Json请求
|
||||||
|
*
|
||||||
|
* @param exchange HTTP请求
|
||||||
|
*/
|
||||||
|
public static boolean isJsonRequest(ServerWebExchange exchange) {
|
||||||
|
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||||
|
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取request内的body
|
||||||
|
*
|
||||||
|
* 注意一个request只能读取一次 读取之后需要重新包装
|
||||||
|
*/
|
||||||
|
public static String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
|
||||||
|
// 获取请求体
|
||||||
|
Flux<DataBuffer> body = serverHttpRequest.getBody();
|
||||||
|
AtomicReference<String> bodyRef = new AtomicReference<>();
|
||||||
|
body.subscribe(buffer -> {
|
||||||
|
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
||||||
|
DataBufferUtils.release(buffer);
|
||||||
|
bodyRef.set(charBuffer.toString());
|
||||||
|
});
|
||||||
|
return bodyRef.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中读取request内的body
|
||||||
|
*
|
||||||
|
* 注意要求经过 {@link ServerWebExchangeUtils#cacheRequestBody(ServerWebExchange, Function)} 此方法创建缓存
|
||||||
|
* 框架内已经使用 {@link GlobalCacheRequestFilter} 全局创建了body缓存
|
||||||
|
*
|
||||||
|
* @return body
|
||||||
|
*/
|
||||||
|
public static String resolveBodyFromCacheRequest(ServerWebExchange exchange) {
|
||||||
|
DataBuffer buffer = (DataBuffer) exchange.getAttributes().get(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
|
||||||
|
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
|
||||||
|
return charBuffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置webflux模型响应
|
* 设置webflux模型响应
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue