5、自定义断言工厂
自定义断言工厂需要继承AbstractRoutePredicateFactory
类,重写apply方法的逻辑,在apply方法中可以通过exchange.getRequest()拿到ServerHttpRequest对象,从而可以获取到请求的参数、请求方式、请求头等信息
要求:
- 必须spring组件bean
- 类必须加上
RoutePredicateFactory
作为结尾 - 继承
AbstractRoutePredicateFactory
- 必须声明静态内部类,声明属性来接受 配置文件中的信息
- 需要结合
shortcutFieldOrder
来进行绑定 - 通过apply进行逻辑编写,true就是匹配成功,false就是匹配失败
@Component public class CheckNameRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckNameRoutePredicateFactory.Config> { public CheckNameRoutePredicateFactory() { super(CheckNameRoutePredicateFactory.Config.class); } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("name"); } @Override public Predicate<ServerWebExchange> apply(CheckNameRoutePredicateFactory.Config config) { return new GatewayPredicate() { @Override public boolean test(ServerWebExchange exchange) { return "YangLi".equals(config.getName()); } }; } /** * 用于接受配置文件中 断言的信息 */ @Validated public static class Config { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } }
yml文件加上
- CheckName=YangLi
测试即可。
6、内置过滤器工厂(局部)
由于内置过滤器工厂太多,我这里随便列几个,想看全部内置过滤器工厂,可去官网查看
6.1、添加请求头
- AddRequestHeader=X-Request-red, red
进行测试
@RequestMapping("/header") public String header(@RequestHeader("X-Request-red") String color){ return color; }
结果:
成功返回red
6.2、添加请求参数
- AddRequestParameter=color, blue
进行测试
@RequestMapping("/parameter") public String parameter(@RequestParam("color") String color){ return color; }
结果:
成功返回blue
6.3、为匹配的路由统一添加前缀
- PrefixPath=/mall-order #前缀,对应微服务需要配置context-path
mall-order中需要配置
server: servlet: context-path: /mall-order
6.4、重定向
- RedirectTo=302, https://www.baidu.com/ #重定向到百度
7、自定义过滤器工厂(局部)
- 继承
AbstractGatewayFilterFactory
- 自定义的名称要以GatewayFilterFactory结尾
- 交给spring管理
例子:请求后面的参数name=YangLi才可以
- CheckAuth=YangLi #自定义拦截器,必须?name=YangLi
@Component public class CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> { public CheckAuthGatewayFilterFactory() { super(CheckAuthGatewayFilterFactory.Config.class); } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("value"); } @Override public GatewayFilter apply(CheckAuthGatewayFilterFactory.Config config) { return (exchange, chain) -> { String name = exchange.getRequest().getQueryParams().getFirst("name"); if (StringUtils.isNotBlank(name)){ if (config.getValue().equals(name)){ return chain.filter(exchange); }else{ // 返回404 exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND); return exchange.getResponse().setComplete(); } } return chain.filter(exchange); }; } /** * 用于接受配置文件中 过滤器的信息 */ @Validated public static class Config { private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } } }
8、全局过滤器
局部过滤器和全局过滤器的区别?
局部:局部针对某个路由,需要在路由中进行配置
全局:针对所有路由请求,一旦定义就会全局使用
9、自定义全局过滤器
只需要实现GlobalFilter
接口即可
@Component public class LogGlobalFilter implements GlobalFilter { Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { logger.info(exchange.getRequest().getPath().value()); return chain.filter(exchange); } }
10、请求日志记录(Reactor Netty访问日志)
要启用Reactor Netty访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true
它是java系统属性,不是Spring Boot属性
进行访问,结果会打印日志信息
2022-07-01 15:32:12.140 INFO 15400 --- [ctor-http-nio-2] reactor.netty.http.server.AccessLog : 0:0:0:0:0:0:0:1 - - [01/Jul/2022:15:32:11 +0800] "GET /order-server/order/parameter HTTP/1.1" 200 4 8889 942 ms
11、跨域相关配置
前后端分离需要跨域,所以我们直接在网关这里进行配置
yml方式配置:
spring: cloud: gateway: globalcors: cors-configurations: '[/**]': # 允许访问的资源 allowedOrigins: "*" #跨域允许来源 allowedMethods: - GET - POST
配置类的方式
@Configuration public class CorsConfig { @Bean public CorsWebFilter corsWebFilter(){ CorsConfiguration corsConfiguration = new CorsConfiguration(); // 允许的请求头参数 corsConfiguration.addAllowedHeader("*"); // 允许的method corsConfiguration.addAllowedMethod("*"); // 允许的来源 corsConfiguration.addAllowedOrigin("*"); // 允许访问的资源 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**",corsConfiguration); return new CorsWebFilter(source); } }
12、整合sentinel流控降级
网关作为内部系统外的一层屏障,对内起到一定的保护作用,限流便是其中之一,网关层的限流可以简单的针对不同路由进行限流,也可针对业务的接口进行限流,或者根据接口的特征分组限流。
1、添加依赖
<!--sentinel整合gateway的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> </dependency> <!--sentinel的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
2、添加配置
sentinel: transport: dashboard: 127.0.0.1:8010
3、运行并进入控制台:
测试简单流控规则(一秒钟访问两次将会被限流):
在浏览器进行访问并快速刷新,触发流控规则
名词解读:
- Busrst size 宽容次数,比如设置为1,表示一秒钟访问3次以上被限流
- 间隔 比如间隔设置为2,则表示2秒时间内访问次数大于2则被流控
针对请求属性
Client IP 根据客户端ip地址进行流控
- 精确 ------- 精确匹配你填的匹配串进行流控
- 子串 --------包含匹配串
- 正则 --------- 可以填入正则表达式
Remote Host 根据远程域名进行流控
Header:根据请求头名字匹配对应值进行流控
URL参数和Cookie方式与上述雷同
新建api分组(针对API接口流控)
新增流控规则,选择刚刚新加的api分组
进行测试发现,针对这两个接口发生流控,其他接口无流控
降级规则
当然,相应api也可以配置降级规则
系统规则
这个与sentinel配置系统保护用法一致。
自定义流控异常返回信息
配置类方式:
@Configuration public class GatewayConfig { @PostConstruct public void init(){ BlockRequestHandler blockRequestHandler = new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { HashMap<String,String> map = new HashMap<>(10); map.put("code", HttpStatus.TOO_MANY_REQUESTS.toString()); map.put("message","限流了"); // 自定义异常处理 return ServerResponse.status(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(map)); } }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); } }
yml方式
spring: application: name: api-gateway cloud: gateway: scg: fallback: mode: response response-body: '{"code":403,"mess":"限流了"}'