1,全局过滤器
SpringGate网关提供了31种过滤器,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。
1.1:全局过滤器作用
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilter通过配置定义,处理逻辑是固定的;
而GlobalFilter的逻辑需要自己写代码实现。
定义方式是实现GlobalFilter接口。
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
在filter中编写自定义逻辑,可以实现下列功能:
- 登录状态判断
- 权限校验
- 请求限流等
1.2:自定义全局过滤器
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
- 查看请求路径是否匹配,如果匹配上模拟没有权限进行拦截
- 如果路径和判断条件不匹配进行放行,即可访问对应的服务
如果同时满足则放行,否则拦截
@Component
public class DemoFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1 获得请求路径
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
System.out.println(path);
// 2 处理异常
if("/service-consumer/feign/echo/abc".equals(path)) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
DataBuffer wrap = response.bufferFactory().wrap("没有权限".getBytes(StandardCharsets.UTF_8));
return exchange.getResponse().writeWith(Flux.just(wrap));
}
// 3 放行
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
System.out.println("最后处理");
}));
}
@Override
public int getOrder() {
return 1;
}
}
同时看到也实现了Ordered接口,该接口的作用是在一个项目中肯定不止一个全局过滤器如果存在多个全局过滤器该优先执行哪个吗?我们可以通过实现该接口控制全局过滤器执行优先级!
Gateway 通过 GlobalFilter 编写全局过滤器, 通过Ordered 编写过滤器的优先级(越大,优先级越低)
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
也可以不实现Ordered接口,实现注解方式
@Order(-1):-1可以进行更改
1.3:过滤器执行顺序、
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter
请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器:
排序的规则是什么呢?
- 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
- 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
- 当过滤器的order值一样时,会按照** defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。**
三者排序详细内容,可以查看Spring源码:
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()
方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()
方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链
2:跨域问题
2.1:什么是跨域问题
跨域:域名不一致就是跨域,主要包括:
- 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
- 域名相同,端口不同:localhost:8080和localhost8081
浏览器端请求域名不一样,请求域名相同,服务的端口号又不一致 就会造成跨域问题
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS
2.2:示例跨域问题
可以在浏览器控制台看到下面的错误:
从localhost:8090访问localhost:10010,端口不同,显然是跨域的请求。
2.3:解决跨域问题
在gateway服务的application.yml文件中,添加下面的配置:
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
像网关处理跨域采用的同样是CORS方案:这种方案采用的options请求也会被拦截,该请求会将浏览器端发起一次询问到服务器端,问问是否可以进行请求跨域,将该询问的请求放开即可!
allowedOrigins: # 允许哪些网站的跨域请求
可以将具体允许得进行配置放行
allowedMethods: # 允许的跨域ajax的请求方式
像一些get,post,delete,put,等请求,可以进行配置
allowedHeaders: "*" # 允许在请求中携带的头信息
允许请求头携带信息
allowCredentials: true # 是否允许携带cookie
允许请求中携带cookie信息
maxAge: 360000 # 这次跨域检测的有效期
这个是上面说到,每次ajax请求都会通过CORS方案发起options请求方案进行询问,如果有个小伙子就想一直发ajax那么每次都会发送options显然会造成服务的压力增大,CORS方案性能会有一定损耗,为了减少这种损耗,设置有效期,有效期范围内不再进行请求询问!
'[/**]':拦截一切请求
版权归原作者 爱吃豆的土豆 所有, 如有侵权,请联系我们删除。