7.Gateway

8.Gateway

8.1.介绍

8.1.1.网关介绍

网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁

image-20230526125545541

没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的ip:port,如果user-service并发比较大,则无法完成负载均衡。

有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的ip:prot),这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可以实现token拦截,权限验证,限流等操作。

8.1.2.Gateway简介

GatewaySpringCloud官方提供的用来取代zuul(netflix)的新一代网关组件(zuul的本质是一组过滤器,根据自定义的过滤器顺序来执行)

基于spring5.x、springboot2.x 和ProjectReactor等技术。

目地是让路由更加简单、灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重试,自义定过滤器等token校验ip黑名单等

SpringCloudGateway作为SpringCloud生态的网关,目标是替代Zuul,在SpringCloud2.0以上的版本中,没有对新版本的zuul2.0以上的最新高性能版本进行集成,仍然还是使用的zuul1.x,非Reactor模式的老版本。

为了提升网关的性能,SpringCloudGateway是基于webFlux框架实现的,webFlux框架底层则使用了高性能的Reactor模式通信框架的Netty

8.1.3.特征与功能

1.建立在SpringFramework5ProjectReactorSpringBoot2.0之上

2.能够匹配任何请求属性上的路由

3.谓词和过滤器特定于路由

4.Hystrix断路器集成。

5.SpringCloudDiscoveryClient集成

6.易于编写的谓词和过滤器

7.请求速率限制

8.路径改写

8.1.4.工作流程

image-20230526132826879

1客户端向springcloudGateway发出请求,然后在GatewayHandlerMapping 中找到与其请求相匹配的路由,将其发送到GatewayWebHandle

Handler再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。

过滤器之间用虚线分开是因为过滤器可能会在发送爱丽请求之前【pre】或之后【post】执行业务 逻辑,对其进行加强或处理。

Filter在【pre】类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等

在【post】类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着非常重要的作用。

总结:核心逻辑就是路由转发+执行过滤器链

8.1.5.三大核心概念

①Route(路由)

路由信息的组成: 由一个ID、一个目的URL、一组断言工厂、一组Filter组成。

如果路由断言为真,说明请求URL和配置路由匹配。

②Predicate(断言)

SpringCloudGateway中的断言函数输入类型是Spring5.0框架中的 ServerWebExchange

SpringCloudGateway的断言函数允许开发者去定义匹配来自于HttpRequest 中的任何信息比如请求头和参数

③Filter(过滤)

一个标准的SpringWebFilterservletlistenerfilter以及interceptor组成。

SpringCloudGateway中的Filter分为两种类型的 Filter

  • GatewayFilter:针对某一个路由(路径)
  • GlobalFilter:针对全局

8.1.6.Nginx与Gateway的区别

Nginx在做路由、负载均衡、限流之前都有修改nginx.conf的配置文件,把需要负载均衡, 路由,限流的规则加在里面。(nginx做tomcat的负载均衡)

gateway则是自动的负载均衡和路由gatewayeureka高度集成,实现 自动的路由,和Ribbon结合,实现了负载均衡,gateway也能轻易的实现限流和权限验证。

Nginxgateway的性能高一点。

本质区别就是:

  • Nginx:服务器级别的
  • Gateway:项目级别的

image-20230526133804696

8.2.快速入门

没有实现过滤功能

8.2.1.搭建login-service

①选择依赖

image-20230526134749592

只选择web即可。

②修改配置文件

image-20230526134104047

③添加controller类

image-20230526134427595

8.2.2.搭建Gateway-server

①选择依赖

image-20230526134617060

只需要选择gateway即可。

②修改配置文件

image-20230526135823637

8.2.3.搭建eureka-server

这里和上面的一样,不做多重复

8.2.4.访问测试

http://localhost/login

http://localhost:8001/login

返回出现token即为成功。

8.3.路由

8.3.1.配置方式之代码方式

image-20230526170743705

访问测试:localhost:80/path路径

8.3.2.配置方式之yml方式

image-20230526171945826

8.3.3.动态路由

默认情况下Gateway会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

需要注意的是uri的协议为lb(load Balance),表示启用Gateway的负载均衡功能。

lb://服务名称SpringCloudGateway在微服务中自动为我们创建的负载均衡uri

例:lb://login-service

8.3.4.动态路由使用

改造刚才的例子

Gateway-server改造:

image-20230526183057827

image-20230526183111447

login-service改造:

image-20230526183140622

image-20230526183149260

访问测试:http://localhost/login-service/login

http://localhost:80/服务名称/path路径

出现token即为成功。

8.4.断言

断言就是一些布尔表达式,满足条件的返回true,不满足的返回false。

SpringCloudGateway将路由作为SpringWebFluxHandlerMapping基础架构的一部分进行匹配。

SpringCloudGateway包括许多内置的路由断言工厂。

所有这些断言都与HTTP请求的不同属性匹配。可以将多个路由断言可以组合使用SpringCloudGateway创建对象时,使用RoutePredicateFactory创建 Predicate对象,Predicate对象可以赋值给Route

配置规则

image-20230526233532171

使用

spring:
    cloud:
        gateway:
        enabled: true #开启网关,默认是开启的
        routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
            - id: user-service #路由 id,没有要求,保持唯一即可
            uri: lb://provider #使用 lb 协议 微服务名称做负均衡
            predicates: #断言匹配
                - Path=/info/** #和服务中的路径匹配,是正则匹配的模式
                - After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
                - Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之前的请求
                -Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai]
                #此断言匹配发生在指定日期时间之间的请求
                - Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
                - Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
                - Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
                - Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数:要匹配的 HTTP 方法
                - Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个可选的 regexp(一个 Java 正则表达式)。
                - RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1),这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)

还有一个访问权重的设置,比如说:

80%的请求,由https://weighthigh.org 这个 url 去处理

20%的请求,由https://weightlow.org 去处理

spring:
	cloud:
        gateway:
            routes:
                - id: weight_high
                    uri: https://weighthigh.org
                    predicates:
                        - Weight=group1, 8
                - id: weight_low
                    uri: https://weightlow.org
                    predicates:
                        - Weight=group1, 2

8.5.过滤

gateway的过滤器和Servlet的过滤器功能差不多,路由过滤器可以用于修改进入Http请求和返回Http响应

8.5.1.分类

生命周期分类

pre:在业务逻辑之前

post:在业务逻辑之后

种类分类

GatewayFilter需要配置某个路由才能过滤。

如果需要使用全局路由,需要配置DefaultFilters

GlobalFilter全局过滤器,不需要配置路由,系统初始化作用到所有路由上 全局过滤器

8.5.2.自定义过滤

在上面的测试中添加一个类测试即可。

image-20230527093447555

8.5.3.IP认证拦截

修改上面的自定义过滤类即可。

image-20230527100727888

测试访问http://127.0.0.1/login

image-20230527100637430

8.6.限流

限制一段时间内,用户访问资源的次数,减轻服务器压力。

限流分为

1.IP限流(一段时间内只能访问x次,超过则限制不让访问,过一段时间才可继续访问)

2.请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个api/url,一个服务)

结合redis实现

①添加依赖

SpringCloudGateway已经内置了一个 RequestRateLimiterGatewayFilterFactory

RequestRateLimiterGatewayFilterFactory的实现依赖于Redis,所以需要引入spring-boot-starter-data-redis-reactive这个依赖。

<!--限流要引入 Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

②添加配置

server:
    port: 80
spring:
    application:
        name: gateway-server
	cloud:
		gateway:
			routes:
                - id: user-service-router
                uri: lb://login-service
                predicates:
                    - Path=/login
                filters:
                    - name: RequestRateLimiter
                        args:
                            key-resolver: '#{@hostAddrKeyResolver}' #用于限流的键的解析器的Bean对象的名字。使用SpEL表达式根#{@beanName}从Spring容器中获取Bean对象
                            redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
                            redis-rate-limiter.burstCapacity: 3 #令牌桶容量
	redis: #redis 的配置
        host: localhost
        port: 6379
        database: 0
eureka:
    instance:
        instance-id: ${spring.application.name}:${server.port}
        prefer-ip-address: true
    client:
        service-url:
            defaultZone: http://localhost:8761/eureka

③添加config类

@Configuration
public class RequestRateLimiterConfig {
    /*
    * IP 限流
    * 把用户的 IP 作为限流的 Key
    */
    @Bean
    @Primary
    public KeyResolver hostAddrKeyResolver() {
        return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    /**
    * 用户 id 限流
    * 把用户 ID 作为限流的 key
    */
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }
    /**
    * 请求接口限流
    * 把请求的路径作为限流 key
    */
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
}

④访问测试

快速访问多次:http://localhost/login,之后出现429错误即为成功

8.7.跨域

代码实现

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

配置文件实现

spring:
    cloud:
        gateway:
            globalcors:
                corsConfigurations:
                    '[/**]': // 针对哪些路径
                    allowCredentials: true #可以携带cookie
                    allowedHeaders: '*'
                    allowedMethods: '*'
                    allowedOrigins: '*
posted @   22-10-21  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示