配置类:
/**
* 网关配置类
*
* @author lyf
* @date 2022/01/01 00:00 周六
**/
@Configuration(proxyBeanMethods = false)
public class GatewayConfig {
/**
* context-path
*/
@Value("${server.servlet.context-path:fast-common-gateway}")
private String prefix;
/**
* 过滤server.servlet.context-path属性配置的项目路径,防止对后续路由策略产生影响,因为gateway网关不支持servlet
*
* @return
*/
@Bean
public WebFilter apiPrefixFilter() {
return (exchange, chain) ->
{
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getRawPath();
path = path.startsWith(prefix) ? path.replaceFirst(prefix, "") : path;
ServerHttpRequest newRequest = request.mutate().path(path).build();
return chain.filter(exchange.mutate().request(newRequest).build());
};
}
/**
* 跨域配置
*
* @return
*/
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(false);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
@Bean
public GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler();
}
}
过滤器(关键):
/**
* 自定义全局过滤器类
*
* @author lyf
* @date 2022/01/01 00:00 周六
**/
@Slf4j
@Component
public class AccessLogGlobalFilter implements GlobalFilter, Filter {
private static final String START_TIME = "startTime";
private static final String X_REAL_IP = "X-Real-IP";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(START_TIME, System.currentTimeMillis());
return chain
// 继续调用filter
.filter(exchange)
// filter的后置处理
.then(
Mono.fromRunnable(
() -> {
Long startTime = exchange.getAttribute(START_TIME);
if (startTime != null) {
Long executeTime = (System.currentTimeMillis() - startTime);
// 解决网关转发到微服务时的跨域问题
exchange.getResponse().getHeaders().entrySet().stream()
.filter(entry -> (entry.getValue() != null && entry.getValue().size() > 1))
.filter(entry -> HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN.equals(entry.getKey()) || HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS.equals(entry.getKey()))
.forEach(entry -> {
entry.setValue(Collections.singletonList(entry.getValue().get(1)));
});
// 调试模式下输出访问日志
List<String> ips = exchange.getRequest().getHeaders().get(X_REAL_IP);
String ip = ips != null ? ips.get(0) : null;
String host = exchange.getRequest().getURI().getHost();
String method = exchange.getRequest().getMethod().name();
String path = exchange.getRequest().getURI().getRawPath();
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
int code = exchange.getResponse().getStatusCode() == null ? 500 : exchange.getResponse().getStatusCode().value();
log.debug("IP:[{}],Host:[{}],Method:[{}],Path:[{}],QueryParams:{},StatusCode:{},Time:{}ms"
, ip, host, method, path, queryParams, code, executeTime);
log.debug("==================================================================================================================");
}
}
)
);
}
/**
* 解决网关转发到微服务时的跨域问题
*
* @param servletRequest
* @param servletResponse
* @param filterChain
*/
@SneakyThrows
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
String method = request.getMethod();
if (SaHttpMethod.OPTIONS.name().equalsIgnoreCase(method)) {
servletResponse.getOutputStream().write("Success".getBytes(StandardCharsets.UTF_8));
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
}