网关介绍1.为什么使用网关在之前的学习中,我们通过Eureka,Nacos解决了服务注册,服务发现的问题,使用SpringCloudLoadBalance解决了负载均衡的问题,使用OpenFeign解决了远程调用的问题但是当前所有的微服务接口都是对外暴露的,可以通过外部直接访问,为了保证对外服务的安全,服务端实现的微服务接口通常带有一定的权限校验机制,由于使用了微服务,原本一个应用的多个模块拆分成了多个应用,我们不得不实现多次校验逻辑,当这套逻辑需要修改的时候,我们需要修改多个应用,加重了开发人员的负担,针对这一问题,我们使用API网关来解决2.什么是API网关API网关(简称网关)也是一个服务,通常是后端服务的唯一入口,他的定义类似于设计模式中Facade模式(门面模式).他类似于整个微服务架构的门面,所有的外部客户端访问,都需要经过他来进行调整和过滤网关的核心功能:1.权限控制:作为微服务的入口,对用户进行权限校验,如果校验失败则进行拦截2.动态路由:一切请求先经过网关,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务3.负载均衡:把路由的目标服务有多个时,还需要做负载均衡4.限流:请求流量高时,按照网关中配置微服务能够接受的流量进行放行,避免服务压力过大3.常见网关实现业界常见的网关方式有很多,技术方案也比较成熟,比如Nginx,Kong,Zuul等,常见的两种方案:1.Zuul:Zuul是Netflix开源的一个API网关组件,是Spring Cloud Netflix子项目的核心组件之一,他可以和Eureka,Ribbon,Hystrix等组件配合使用.2.SpringCloudGatewaySpringCloudGateway是Springcloud的一个全新的API项目,基于SpringSpringBoot等技术开发,目的是替换Zuul.旨在为微服务架构提供一种简单而有效的途径来转发请求,并为他们提供横切关注点,比如:安全性,监控/指标和弹性SpringCloudGateway1.网关开发的主要步骤1.创建项目2.引入网关相关的依赖3.启动类4.配置文件5.测试2.Route Predicate Factories1.Predicate基本语法Predicate是Java8提供的一个函数式编程接口,他接受一个参数并返回一个布尔值,用于条件过滤,请求参数的校验FunctionalInterface public interface PredicateT{ boolena test(T t); }Predicate的其他写法1.内置函数public class PredictTest{ public static void main(String[] args){ PredicateString predicate new PredicateString(){ Override public boolean test(String s){ return s.isEmpty(); } }; System.out.println(predicate.test()); System.out.println(predicate.test(bite)); } }2.lambda写法public class PredictTest{ public static void main(String[] args){ PredicateString predicate s - s.isEmpty(); System.out.println(predicate.test()); System.out.println(predicate.test(bite)); } }PredicateString predicate s-s.isEmpty();也可以写成PredicateString isEmpty String::isEmpty;2.Route Predicate FactoriesRoute Predicate Factories(路由断言工厂, 也称之为路由谓词工厂,此处的谓词表示一个函数)在SpringCloudGateway中predicate提供了路由规则的匹配机制我们在配置文件中写的断言规则只是字符串,这些字符串会被Route Predicate Factories读取并处理,转换为路由判断的条件SpringCloudGateway默认提供了很多Route Predicate Factories,这里Predicate会分别匹配HTTP请求的不同属性,并且多个Predicate可以通过and逻辑进行组合名称说明After这个工厂需要一个日期时间(Java的ZonedDateTime对象),匹配指定日期之后的请求Before匹配指定日期之前的请求Between匹配两个指定时间之间的请求datetime2 的参数必须在datetime1之后Cookie请求中包含指定Cookie,且该Cookie值符合指定的正则表达式Header请求中包含指定Header,且该Header值符合指定的正则表达式Host请求必须是访问某个host(根据请求中的Host字段进行匹配)Method匹配指定的请求方式Path匹配指定规则的路径RemoteAddr请求者的IP必须为指定范围3.Gateway Filter Factories(网关过滤工厂)Predicate决定了请求由哪一个路由处理,如果在请求处理前后需要加一些逻辑,这就是Filter(过滤器)的作用范围了Filter根据作用时间划分:Pre类型过滤器 路由处理之前执行(请求转发到后端服务之前执行).在Pre类型过滤器中可以做鉴权,限流等Post类型过滤器 请求执行完成之后,将结果返回给客户端之前执行SpringCloudGateway内置了很多Filter,用于拦截和链式处理web请求,比如权限校验,访问超时等设定SpringCloudGateway从作用范围上 把Filter可以分为GatewayFilter和GlobalFilterGatewayFilter:应用到一个路由或者一个分组的路由上GlobalFilter:应用到所有的路由上,也就是对所有的请求生效GatewayFilter说明SpringCloudGateway提供的Filter非常多,下面给出一些常见的Filter说明名称说明AddRequestHeader为当前请求添加HeaderAddRequestParameter为当前请求添加请求参数AddResponseHeader为响应结果添加HeaderRemoveRequestHeader从当前请求删除某个HeaderRemoveResponseHeader从响应结果删除某个HeaderRequestRateLimiter为当前网关的所有请求执行限流过滤,如果被限流,默认会响应HTTP429-TooManyRequests默认提供了RedisRateLimiter的限流实现,采用令牌桶算法现限流功能.Retry针对不同的响应进行重试.当后端服务不可用时,网关会根据配置参数来发起重试请求.RequestSize设置允许接收最大请求包的大小,如果请求包大小超过设置的值,则返回 413 Payload TooLarge.请求包大小,单位为字节,默认值为5M.默认过滤器添加一个filter并将其应用于所有路由,这个属性需要一个filter的列表,常见的限流算法:1.固定窗口2.滑动窗口3.漏桶算法(生产者消费者模型 类似消费者以一速率进行漏) 对应激流量的处理不好4.令牌桶算法 每秒钟n个令牌往里放Default Filters前面的filter添加在指定路由上,所以只对当前路由生效,如需要对全部路由生效,可以使用spring.cloud.gateway.default-filters 来在配置文件中进行配置GlobalFilterGlobalFilter是SpringCloudGateway中的全局过滤器,他和GatewayFilter的作用是相同的.GlobalFilter是应用到所有的路由请求上,全局过滤器通常用于实现与安全性,性能监控和日志记录等相关的全局功能SpringCloudGateway内置的全局过滤器也有很多,比如:1.Gateway Metrics Filter: 网关指标,提供监控指标2.Forword Routing Filter:用于本地forward,请求不转发到下游服务器3.LoadBalance Client Filter: 针对下游服务,实现负载均衡4.过滤器执行顺序一个项目中,既有GatewayFilter又有GlobalFilter时,执行的先后顺序是什么?请求路由后,网关会把当前项目中的GatewayFilter和GlobalFilter合并到一个过滤器链中,并进行排序,依次执行过滤器每一个过滤器必须指定一个iint类型的order值,默认值为0,表示该过滤的优先级,order值越小,优先级越高,执行顺序越靠前1.Filter通过实现Order接口或者添加Order注解来指定order值2.SpringCloudGateway提供的Filter由Spring指定,用户也可以自定义filter,由用户指定3.当过滤器的order值一样时,会按照Default gatewayglobal的顺序执行5.自定义过滤器SpringCloudGateway提供了过滤器的拓展功能,开发者可以根据实际业务来自定义过滤器,同样自定义过滤器也支持GatewayFilter和GlobalFilter两种定义GatewayFilterSlf4j Component public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactoryCustomConfig implements Ordered { public CustomGatewayFilterFactory() { super(CustomConfig.class); } Override public GatewayFilter apply(CustomConfig config) { return new GatewayFilter() { /** * * param exchange http请求和响应的契约信息 提供了对Http请求和响应的访问 * param chain 过滤器链 * Mono:reactor的核心类 数据流发布者 mono最多只能触发一个事件 可以用在异步完成任务时发送通知 * Mono.runnable()创建一个runnable的元素的数据流 * return */ Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { //pre 类型 post类型过滤器 log.info(pre filter config {},config); //pre类型过滤器代码逻辑 return chain.filter(exchange).then(Mono.fromRunnable(()-{ log.info(post filter ....); })); } }; } Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } }针对这个Filter配置,使用CustomConfig定义Data public class CustomConfig{ private String name; }代码说明:1.类名统一以GatewayFilterFactory结尾,因为默认情况下,过滤器的name会使用该定义类的前缀,这里的nameCustom(yml配置中使用)2.apply方法中,同时包含Pre和Post过滤,then方法是请求执行结束之后处理的3.CustomConfig是一个配置类,该类只有一个属性name和yml配置对应4.该类需要交给Spring管理,所以需要加Service注解5.getOrder表示该过滤器的优先级,值越大,优先级越低配置过滤器spring: cloud: gateway: routes:#网关路由配置 - id: product-service uri: lb://product-service predicates: #路由条件 - Path/product/ ** filters: - name: Custom args: name: custom filter自定义GlobalFilterGlobalFilter的实现比较简单,他不需要额外的配置,只需要实现GlobalFilter接口,自动会过滤所以的FilterSlf4j Component public class CustomGlobalFilter implements GlobalFilter, Ordered { Override public MonoVoid 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 Ordered.LOWEST_PRECEDENCE; } }服务部署1.确认配置2.打包3.上传jar包4.开放端口号5.测试