目录
网关介绍(其实更像是学校门口的保安,假如你去xx楼,不能每个地方都有保安)
Route Predicate Factories(路由断言工厂)
Gateway Filter Factories(网关过滤工厂)
AddRequestHeaderGatewayFilterFactory-给请求header加参数
AddResponseHeaderGatewayFilterFactory -添加响应
网关介绍(其实更像是学校门口的保安,假如你去xx楼,不能每个地方都有保安)
LoadBalance解决了负载均衡问题,使用OpenFeign解决了远程调用的问题
但是当前所有的微服务接口都是直接对外暴露的,可以直接通过外部访问,为了保证对外服务的安全性,通常微服务接口带有一定的校验机制,由于使用了微服务,原先一个应用模块,拆分成了多个应用,让我们不得不实现多次校验逻辑,当这套逻辑需要修改时候,我们需要修改多个应用,增加了开发人员的负担。
网关核心功能
1.权限控制 -会对所有服务进行一个权限的校验
2.动态路由 -会根据用户请求,把请求转发给某个服务
3.负载均衡 -当网关决定是订单系统,然后会决定把请求发给那些实例。
4.限流 -每个微服务能承担的流量有限,要针对特定场景,进行限流
常见网关实现 :Nginx,Gateway,Zuul
Zuul是Netfix开源的一个API网管组件,Spring Cloud Netflix子项目的核心组件之一,他可以和Eureka,Ribbon,Hystrix等组件配合使用,然后Netfix在2018年,宣布一部分产品进入维护状态,不再进行新特性的开发,这其中的组件就保护zuul
SpringCloudGateway:是spring_cloud一个全新的API网关项目,基于Spring和SpringBoot等技术开发,目的就是替换掉Zuul。
网关开发:
1.创建项目
2.引入网关相关依赖
3.写启动类
4.配置文件
5.测试
Route Predicate Factories(路由断言工厂)
Predicate
Predicate是java8提供的一个函数式编程接口,她用于接收一个参数,并且返回一个布尔值,用于条件过滤,请求参数的校验。
package predicate; import org.junit.Test; import java.util.function.Predicate; public class PredicateTest { @Test public void test0(){ String a=""; System.out.println(a.isEmpty() ); } @Test public void test(){ Predicate<String>predicate=new StringPredicate(); System.out.println(predicate.test("")); } //匿名内部类 @Test public void test2(){ Predicate<String> predicate=new Predicate<String>() { @Override public boolean test(String s) { return s==null||s.isEmpty(); } }; System.out.println(predicate.test("")); System.out.println(predicate.test("aa")); } //lambda表达式 @Test public void test3(){ Predicate<String> predicate=s->s==null ||s.isEmpty(); System.out.println(predicate.test("")); System.out.println(predicate.test("aa")); } //非 negata @Test public void test4(){ Predicate<String> predicate=s->s==null||s.isEmpty(); System.out.println(predicate.negate().test("")); System.out.println(predicate.negate().test("aa")); } //or 判断字符串为aa或者bb @Test public void test5(){ Predicate<String> predicate=s->"aa".equals(s); Predicate<String> predicate2=s->"bb".equals(s); System.out.println(predicate.negate().test("")); System.out.println(predicate.negate().test("aa")); System.out.println(predicate.or(predicate2).test("")); System.out.println(predicate.or(predicate2).test("aa")); } //and 判断字符串为aa或者bb,不为空,且由数字组成,比如"12","34" @Test public void test6(){ Predicate<String>predicate=s->s!=null&&!s.isEmpty(); Predicate<String>predicate2=s->s!=null&&s.chars().allMatch(Character::isDigit); System.out.println(predicate.and(predicate2).test("aa")); System.out.println(predicate.and(predicate2).test("123")); } }
表示请求时间,必须要在这个日期之后,格式是一个带时期的格式
在指定日期之前
前面日期要小,后面日期要大,请求要在两个日期之间
接收Cookie的值,还有一个是Cookie的value,value可能是一个值,也有可能是一个表达式
他对应的是Http里面的Header, 值是一个数字类型
请求方式只有get 或者post才满足这个
配置规则我们现在用的就是这个
Gateway Filter Factories(网关过滤工厂)
Predicate决定了请求由哪一个路由处理,如果在请求处理前后需要增加一些逻辑,这就是Filter过滤器的作用范围了
Filter分两种类型:Pre类型和Post类型(根据作用时间划分)
Pre类型:路由处理之前执行(请求转发到后端服务之前执行),在Pre类型过滤器中可以做鉴权,限流等
Post类型过滤器:请求执行完成之后,将结果返回给客户端之前执行
Spring Cloud Gateway中内置了很多Filter,用于拦截和链式处理web请求,比如权限校验,访问超时设定
Spring Cloud Gateway从作用范围上,把Filter可分为GatewayFilter和GloabalFilter
GatewayFilter:应用到单个路由或者一个分组的路由上
GlobalFilter:应用到所有的路由上,也就是对所有的请求生效
在处理前后添加一些逻辑
AddRequestHeader
GatewayFilter
Factory-给请求header加参数
AddResponseHeader
GatewayFilter
Factory -添加响应
Redis针对流量的限制 -限流,
限流算法:
1.固定窗口(假设流量限制,每分钟一千次)
2.限流实现:
下面采用的就是令牌桶,
redis-rate-limiter.replenishRate:10
burstCapacity是令牌桶的容量
limiter.requestedToken:每个请求消耗的令牌
针对下面那个BAD指定状态,进行重试
RequestSize
默认过滤器,对所有路由都适用,可以看到状态码并不影响展示。
GlobalFilter
GlobalFilter是Spring Cloud Gateway中全局过滤器,他和GatewayFilter的作用相同
GlobalFilter会应用到所有的路由请求上,全局过滤器通常用于实现与安全性,性能监控和日志记录等相关的全局功能
Spring Cloud Gateway内置全局过滤器很多 ,如:
1.添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
2.这里的enable默认是false,我们改动为true
它是开启这个监控信息服务。
如何自定义过滤器
自定义GatewayFilter,需要去实现对应的接口GatewayFilterFactory,springBoot默认帮我们实现的抽象类AbstractGatewayFilterFactory,我们可以直接用
(类的内部源码,我们发现,他的类型是C,我们需要在这块接收一些参数,我们之前定的参数是一个字符串)
在自定义网关的时候,遇到个问题
***************************
APPLICATION FAILED TO START
***************************Description:
Parameter 0 of constructor in com.bite.gateway.CustomGatewayFilterFactory required a bean of type 'java.lang.Class' that could not be found.
Action:Consider defining a bean of type 'java.lang.Class' in your configuration.
Process finished with exit code 1这句话,不一定是提醒你,你没加注释,没加载成功,有可能是,你需要某个特定类的Class对象,然后你错误的要求Spring注入一个Class类型的bean.
1.检查构造函数的参数->我是在这里错误的注入了一个class类型的Bean
2.使用Autowired的适当方式
自定义GlobalFilter
package com.bite.gateway; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component @Slf4j public class CustomGlobalFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("Pre Global Filter"); return chain.filter(exchange).then(Mono.fromRunnable(()->{ log.info("Post Global Filter ..."); })); } @Override public int getOrder() { return 0; } }