目录
背景
以下内容主要在原框架的基础上做部分改造,以及新增。改造是因为要兼容原filter等内容,但是实际上自己重新开始做的话也差不多。
实现了微服务下的日志链路追踪以及微服务中请求的耗时监控。
网关
网关中的全局请求过滤器、鉴权过滤器、全局异常处理器改造,增加响应头处理过滤器。
(ps:根据项目不同,过滤器、拦截器、处理器可能不同,但是原理是相同的,当前的系统只需要修改上面三个地方就可以了)
全局请求过滤器
import com.gene.gateway.utils.LogGlobalFilterUtil;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class GatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
ServerHttpResponse serverHttpResponse = exchange.getResponse();
LogGlobalFilterUtil.setThreadContext(serverHttpRequest, serverHttpResponse);
log.info("请求地址:{}", exchange.getRequest().getURI().getPath());
return chain.filter(exchange);
} finally {
ThreadContext.remove(LogGlobalFilterUtil.REQUEST_ID_HEADER);
}
}
@Override
public int getOrder() {
return 0;
}
}
1.在请求和响应头中放入RequestId
2.在ThreadContext中放入RequestId(log4j2 1.x版本用MDC,2.x版本用ThreadContext)
ServerHttpRequest serverHttpRequest = exchange.getRequest();
ServerHttpResponse serverHttpResponse = exchange.getResponse();
LogGlobalFilterUtil.setThreadContext(serverHttpRequest, serverHttpResponse);
避免内存溢出
finally { ThreadContext.remove(LogGlobalFilterUtil.REQUEST_ID_HEADER); }
鉴权过滤器/全局异常处理器改造
跟全局请求过滤器对于request、response和ThreadContext的处理逻辑相同,只是其他业务逻辑不同.
(个人觉得这里并不完善,可以通过改造异步线程池以及设置request的子线程共享去实现在全局请求过滤器中处理一次就可以,本人没有试过,只是有个思路)
响应头处理过滤器
该过滤器的主要作用是处理响应中的header值重复的,因为在网关处理过一次response的header,在各个微服务中也要处理response的header,调用链上多次的处理会导致值重复,所以在返回的时候去重。
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.stream.Collectors;
/**
* @description: 头部信息去重过滤器
* @author: gene
* @date: 2021/11/30 13:14
*/
@Component
@Slf4j
public class HeaderFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(
Mono.defer(() -> {
HttpHeaders httpHeaders = exchange.getResponse().getHeaders();
httpHeaders.forEach((k, v) -> {
if (null != v && v.size() > 1) {
List<String> list = v.stream().distinct().collect(Collectors.toList());
httpHeaders.replace(k, list);
}
});
return chain.filter(exchange);
})
);
}
@Override
public int getOrder() {
// 指定此过滤器位于NettyWriteResponseFilter之后, 待处理完响应体后接着处理响应头
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
}
指定此过滤器位于NettyWriteResponseFilter之后, 待处理完响应体后接着处理响应头
NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1
ThreadContext工具类
import org.apache.logging.log4j.ThreadContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;