赞
踩
Gateway过滤器在实现方式上,有两种过滤器:
spring.cloud.routes.filters
配置在具体的路由下,只作用在当前特定路由上,也可以通过配置 spring.cloud.default-filters让它作用于全局路由上。 spring.cloud.gateway.default-filters
上会对所有路由生效也算是全局的过滤器;但是这些过滤器的实现上都是要实现GatewayFilterFactory接口。不需要再配置文件中配置,作用在所有的路由上
,最终通过 GatewayFilterAdapter包装成 GatewayFilterChain能够识别的过滤器。全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。Spring Cloud Gateway y也提供了几种全局过滤器,同时我们也可以自定义全局过滤器。
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters
ForwardRoutingFilter全局转发过滤器。
ForwardRoutingFilter会查看 exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR的值(一个URI)。如果 URL有转发 scheme(例如forward:///localendpoint),Gateway使用 Spring DispatcherHandler来处理请求。请求 URL的路径部分被转发URL中的路径覆盖。未修改的原始URL将附加到ServerWebExchangeUtils中的列表中。
源码如下:
ReactiveLoadBalancerClientFilter全局负载均衡过滤器。
LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI)。如果该值的 scheme是 lb,比如:lb://app-order ,它将会使用 Spring Cloud的 LoadBalancerClient 来将 微服务名(本例中为app-order)解析成实际的 host和 port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。未修改的原始URL将附加到ServerWebExchangeUtils中的列表中。
#配置 gateway网关
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
# app-order服务路由配置
- id: app-order #路由ID,全局唯一,建议配置服务名。
uri: lb://app-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order/** # 断言,路径相匹配的进行路由
源码如下:
public class ReactiveLoadBalancerClientFilter implements GlobalFilter, Ordered { private static final Log log = LogFactory.getLog(ReactiveLoadBalancerClientFilter.class); private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150; private final LoadBalancerClientFactory clientFactory; private LoadBalancerProperties properties; public ReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) { this.clientFactory = clientFactory; this.properties = properties; } public int getOrder() { return 10150; } public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR); if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) { ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url); if (log.isTraceEnabled()) { log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url); } return this.choose(exchange).doOnNext((response) -> { if (!response.hasServer()) { throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost()); } else { ServiceInstance retrievedInstance = (ServiceInstance)response.getServer(); URI uri = exchange.getRequest().getURI(); String overrideScheme = retrievedInstance.isSecure() ? "https" : "http"; if (schemePrefix != null) { overrideScheme = url.getScheme(); } DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance, overrideScheme); URI requestUrl = this.reconstructURI(serviceInstance, uri); if (log.isTraceEnabled()) { log.trace("LoadBalancerClientFilter url chosen: " + requestUrl); } exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl); } }).then(chain.filter(exchange)); } else { return chain.filter(exchange); } } protected URI reconstructURI(ServiceInstance serviceInstance, URI original) { return LoadBalancerUriTools.reconstructURI(serviceInstance, original); } private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) { URI uri = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR); ReactorLoadBalancer<ServiceInstance> loadBalancer = (ReactorLoadBalancer)this.clientFactory.getInstance(uri.getHost(), ReactorServiceInstanceLoadBalancer.class); if (loadBalancer == null) { throw new NotFoundException("No loadbalancer available for " + uri.getHost()); } else { return loadBalancer.choose(this.createRequest()); } } private Request createRequest() { return ReactiveLoadBalancer.REQUEST; } }
更多全局过滤器查看官方文档。下面我们自定义一个全局过滤器。
在 Gateway服务中,创建自定义全局过滤器类必须实现 GlobalFilter接口
。每一个过滤器都必须指定一个int类型的 order值,order值越小,过滤器优先级越高,执行顺序越靠前。GlobalFilter通过实现 Ordered接口来指定 order值。
模拟一个登录的校验。基本逻辑:如果请求中有 token参数,则认为请求有效,放行。
@Component @Slf4j public class AppCheckAuthGatewayFilter implements GlobalFilter, Ordered { /** * 参考 GlobalFilter接口的实现类 * * @param exchange * @param chain * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("---------执行全局过滤器-----------"); // 请求头或者请求参数中获取token String token = exchange.getRequest().getHeaders().getFirst("token"); //String token = exchange.getRequest().getQueryParams().getFirst("token"); if (StringUtils.isBlank(token)) { log.info("token is null"); ServerHttpResponse response = exchange.getResponse(); response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); // 401 用户没有访问权限 response.setStatusCode(HttpStatus.UNAUTHORIZED); byte[] bytes = HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes(); DataBuffer buffer = response.bufferFactory().wrap(bytes); // 请求结束,不继续向下请求 return response.writeWith(Mono.just(buffer)); } // TODO 校验token进行身份认证 log.info("开始校验token,token={}", token); return chain.filter(exchange); } /** * 当有多个过滤器时, order值越小,越优先先执行 * * @return */ @Override public int getOrder() { return 100; } }
– 求知若饥,虚心若愚。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。