SpringCloud之Gateway组件简介

网关的理解

网关类似于海关或者大门出入都需要经过这个网关。别人不经过这个网关,永远也看不到里面的东西。可以在网关进行条件过滤,比如大门只有对应的钥匙才能入内。网关和大门一样,永远暴露在最外面

不使用网关

  • 前端需要记住每一个服务的IP和port

  • 如果有一个服务部署多台,那么前端需要自行分配

使用网关

  • 前端不需要记每一个服务的IP和port,只需要将请求发送到网关即可,网关根据资源路径做路由跳转

  • 网关中可以做安全控制 比如Token校验、限流等

  • 可以做负载均衡

Gateway的理解

是Spring官网推出的一套网关组件,用来取代Zuul

它的目的是为了让路由跳转更加方便、灵活,还提供了一些强大的过滤器功能。比如:IP黑名单、Token校验等

基于webFlux框架实现,webFlux框架底层使用了高性能的Reactor模式通信框架的Netty


Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和Project Reactor等技术。

Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。

① Gateway工作原理

客户端发送请求到Gatewaty,然后Gateway HandlerMapping通过对比映射,找到与其匹配的路由,将其发送到Gateway WebHandler。Handler再通过指定的过滤器将请求分发到实际的业务逻辑,并返回。

在过滤器中可以做增加代码:

  • 请求之前[pre]做校验等

  • 请求之后[post]做日志输出等

Gateway核心逻辑:根据资源路径做路由转发,并且执行过滤器链。

② Gateway三大核心概念

路由(Route)

和eureka结合做动态路由

组成部分:一个路由ID、一个唯一资源定位符URI、一组断言、一组Filter

如果路由断言为真,那么URL和配置路由匹配

断言(Predicate)

返回一个boolean表达式

过滤器(Filter)

Gateway中的过滤器分为Gateway Filter(针对一个路由)和Global Filter(全局)

在过滤器中可以编写校验规则以及响应的处理

③ Gateway和Nginx区别

Nginx做限流、负载均衡、路由都需要修改nginx.conf配置文件

Gateway和eureka结合,实现了自动路由跳转;和Ribbon集合,实现了负载均衡。Gateway也能够通过配置进行限流的实现

 

路由使用

① 访问流程

② Loing-service

@RestController
public class LoginController {

    @GetMapping("doLogin")
    public String doLogin(String username,String password){
        System.out.println(username+" -> "+password);
        String token = UUID.randomUUID().toString();
        return token;
    }
}

② Gateway-server

gateway依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置路由

server:
  port: 80
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true # 默认开启Gateway
      routes: # 路由组
        - id: login-service-route # 路由ID 保证唯一
          uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符
          predicates: # 断言
            - Path=/doLogin # 和服务中的路径匹配

④ 编程式路由

不借助配置文件,使用编码的方式来实现路由转发

@Configuration
public class RouteConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("anime-id", r->r.path("/anime").uri("https://www.bilibili.com"))
                .route("variety-id",r->r.path("/variety").uri("https://www.bilibili.com"))
                .build();
    }
}

如果在uri后面的资源路径和path中的路由一样,那么gateway不会把path中的路由拼接到uri后面。

编程式和配置文件的方式可以结合使用

动态路由

如果在路由转发时直接将URL写死,从而IP和port也被写死,那么Gateway将无法达到负载均衡的效果。应该是只提供服务名,然后通过这个名字去找对应的服务,从而达到负载均衡的效果

让Gateway服务也注册到注册中心中,那么Gateway就能够拥有所有的服务信息

Gateway会根据注册中心中的服务列表,以每个服务名为路径创建动态路由进行转发

① 第一种实现方式

使用lb(Load Balance)协议,表示启用Gateway的负载均衡功能

server:
  port: 80
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true # 默认开启Gateway
      routes: # 路由组
        - id: login-service-route # 路由ID 保证唯一
          # uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符
          uri: lb://login-service # lb://服务名
          predicates:
            - Path=/doLogin # 和服务中的路径匹配

 调用:http://localhost/doLogin

② 第二种实现方式

使用服务发现,自动创建动态路由从而实现负载均衡

server:
  port: 80
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true # 默认开启Gateway
      discovery:
        locator:
           enabled: true # 开启动态路由
           lower-case-service-id: true # 将注册列表中的服务名小写

断言

在项目启动的时候,Gateway会去加载一些路由断言工厂,例如:After、Query

断言就是给路由增加一些匹配规则,如果发送的请求符合这些规则,就能够去访问,否则404。简单说这些匹配规则也就是一些boolean表达式,要么true进入,要么false拒绝

① 分类

 

② 使用

在配置文件中,对某个路由进行操作。动态路由不能使用断言

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true # 默认开启Gateway
      routes:
        - id: login-service-route
          uri: lb://login-service
          predicates:
            - Path=/doLogin
            - Method=GET,POST # GET,POST请求能够访问
            - After=2022-11-02T17:23:16.423+08:00[Asia/Shanghai] # 在指定时间后才能访问 通过ZonedDateTime获取
            - Query=username,admin. # 必须给username传值 后面的值必须是:adminx

过滤器

Gateway中的过滤器和Servlet里面的过滤器差不多,用户修改进入HTTP请求和HTTP响应

分为GatewayFilter(针对某一个路由)和GlobalFilter(全局过滤)

① 自定义全局过滤器

在自定义过滤器中编写业务逻辑,比如Token校验、限流。

@Component
public class TestFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        RequestPath path = request.getPath();
        // 打印路由以及服务名
        System.out.println(path);
        HttpHeaders headers = request.getHeaders();
        // 获取主机IP
        String ip = headers.getHost().getHostName();
        System.out.println(ip);
        // 获取响应对象
        ServerHttpResponse response = exchange.getResponse();
        // 放过
        return chain.filter(exchange);
    }
}

 定义过滤器顺序

@Component
public class TestFilter implements Ordered {

    @Override
    public int getOrder() {
        // 数字越小 越往前
        return 0;
    }
}

返回值处理

// 获取响应对象
ServerHttpResponse response = exchange.getResponse();
// 设置响应头
response.getHeaders().set("content-Type","application/json;charset=UTF-8");
// 封装返回数据
Map<String,Object> map = new HashMap<>();
map.put("code", 401);
map.put("msg","没有该权限");
ObjectMapper objectMapper = new ObjectMapper();
try {
    // 将map集合转为byte数组
    byte[] bytes = objectMapper.writeValueAsBytes(map);
    // 将byte数组包装成一个数据缓冲包
    DataBuffer wrap = response.bufferFactory().wrap(bytes);
    // 返回
    return response.writeWith(Mono.just(wrap));
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

限流

在一定的时间段内,限制用户的访问频率。

① 限流模型

漏斗算法、令牌通算法、计算器算法、窗口滑动算法

入不敷出:生产令牌的速度赶不上使用的速度

  1. 系统以提前配置好的速率去生产令牌。

  2. 给令牌桶设置一个阈值,当桶满后,多余的令牌直接丢弃

  3. 客户发送请求都需要去拿令牌

  4. 如果没有拿到令牌该请求不能成功访问

  5. 如果拿到令牌将去访问服务,完成业务处理后删除令牌

  6. 当桶中的令牌数达到最低额度时,使用完的令牌返回

② Gateway中的限流

Gateway中已经内置了RequestRateLimiterGatewayFilterFactory,结合Redis做令牌桶算法。需要导入redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

 配置限流规则

@Configuration
public class RequestLimiterConfig {

    /*
      基于IP做限流
     */
    @Bean
    @Primary // 主候选
    public KeyResolver ipKeyResolver(){
        return exchange-> Mono.just(exchange.getRequest().getHeaders().getHost().getHostName());
    }

    /*
      基于API接口最限流
     */
    @Bean
    public KeyResolver apiKeyResolver(){
        return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    }
}

修改配置文件

spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      enabled: true # 默认开启Gateway
      routes:
        - id: login-service-route
          uri: lb://login-service
          predicates:
            - Path=/doLogin
          filters:
            - name: RequestRateLimiter # 过滤器名称
              args:
                key-resolver: '#{@ipKeyResolver}' # Bean对象的名字
                redis-rate-limiter.replenishRate: 1 # 每秒钟生产多少令牌
                redis-rate-limiter.burstCapacity: 3 # 令牌桶中的容量

只针对某一个路由

跨域配置

跨域:CORS同源策略。

因为网关是服务的最边缘,所有的请求都需要走网关,将跨域的配置写在网关。

编程式

@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:
        cors-configurations:
          '[/**]': # 针对那些路径
            allowCredentials: true # 可以携带Cookie
            allowedHeaders: '*'
            allowedMethods: '*'
            allowedOrigins: '*'

面试题相关

什么是微服务网关

Spring Cloud Gateway 是 Spring 官方基于 Spring 5.x,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全性、监视/指标和弹性。

使用Gateway的优势

Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

zuul和spring cloud gateway的对比

  • zuul:是Netflix的,是基于servlet实现的,阻塞式的api,不支持长连接。
  • gateway:是springcloud自己研制的微服务网关,是基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接

gateway的组成

  • 路由 : 网关的基本模块,有ID,目标URI,一组断言和一组过滤器组成
  • 断言:就是访问该旅游的访问规则,可以用来匹配来自http请求的任何内容,例如headers或者参数
  • 过滤器:这个就是我们平时说的过滤器,用来过滤一些请求的,gateway有自己默认的过滤器,具体请参考官网,我们也可以自定义过滤器,但是要实现两个接口,ordered和globalfilter

猜你喜欢

转载自blog.csdn.net/weixin_45934981/article/details/130151588