一、局部过滤器接口耗时(LogTime)
- 命名规则:以GatewayFilterFactory结尾
- 编写接口耗时过滤器
@Slf4j
@Component
public class LogTimeGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
private static long timeSpan = 0;
@Override
public GatewayFilter apply(NameValueConfig config) {
String timeSpanStr = config.getValue();
timeSpan = Long.valueOf(timeSpanStr);
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long startTime = System.currentTimeMillis();
return chain.filter(exchange).then(Mono.fromRunnable(()->{
long endTime = System.currentTimeMillis();
long time = endTime-startTime;
if(time >= timeSpan){
log.debug("{} 耗时:{}",exchange.getRequest().getURI(), time);
}
}));
}
};
}
}
- 在yml文件中加入耗时时长
二、全局Token认证(TokenGlobalFilter)
目的是对所有进入系统的请求或相应进行统一处理
- 创建过滤器类
@Slf4j
@Component
public class TokenFilter implements GlobalFilter, Ordered {
@Value("${cn.smart.tokenx.key}")
private String tokenKey;
private static List<String> whiteList = CollUtil.newArrayList("/api/login", "/api/register");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
URI uri = request.getURI();
String path = uri.getPath().toLowerCase().trim();
//排除白名单的验证
if(whiteList.contains(path)){
return chain.filter(exchange);
}
ServerHttpResponse response = exchange.getResponse();
List<String> tokens = request.getHeaders().get("token");
//验证的是有没有传token
if(ObjectUtil.isEmpty(tokens)){
log.error("请传token");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
String token = tokens.get(0);
//验证的是传的token值是否为空
if(ObjectUtil.isEmpty(token)){
log.error("token 不能为空");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
boolean b = false;
// 验证算法,JWTValidator包含过期的验证,验证比较全面
try {
JWTValidator.of(token).validateAlgorithm(JWTSignerUtil.hs256(tokenKey.getBytes())).validateDate();
b = true;
}catch (Exception ex){
ex.printStackTrace();
log.error("token不正确");
}
if(!b){
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//接着执行下面的过滤器,token还会带到下游,我们的服务还是要用我们之前的token-starter,token-starter功能只保留解析token写入Threadlocal,验证的功能不再需要
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
- 注册全局过滤器,使用@Component注解,Spring会自动扫描并注册Bean
三、全局链路跟踪TraceId日志(TraceIdGlobalFilter)
- 创建全局过滤器,在请求头上带入traceId参数,穿透到下游服务
@Component
@Slf4j
@Order(1)
public class TraceIdFilter implements GlobalFilter {
private static final String TRACE_ID = "traceId";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
List<String> traceIds = request.getHeaders().get(TRACE_ID);
if(ObjUtil.isNotEmpty(traceIds)){
return chain.filter(exchange);
}
String traceId = IdUtil.simpleUUID();
//request.getHeaders().set(TRACE_ID,traceId); //ReadOnlyHttpHeaders UnsupportedOperationException
ServerHttpRequest request2 = request.mutate().header(TRACE_ID,traceId).build();
return chain.filter(exchange.mutate().request(request2).build());
}
- 下游服务使用全链路跟踪Id,配置TraceId过滤器
- 启动类开启SercletComponentScan扫描,启动类上加一个@SercletComponentScan注解
- 配置文件配置日志输出格式