微服务入口组件:Gateway

171 阅读9分钟

Gateway网关

Gateway网关的设计目的是提供一个高性能、安全可靠、可扩展的入口点,为微服务架构中的服务提供者和消费者之间的通信提供统一的接口和管理机制。它可以在多个维度上增强系统的可靠性、可用性、安全性和性能,并提供灵活的路由和转发规则,以适应不同的业务需求。

  1. 路由和转发:Gateway网关能够根据请求的路径、参数、头部信息等进行路由和转发。它可以根据请求的特征将请求动态地路由到相应的微服务实例或后端服务。
  2. 负载均衡:Gateway网关能够根据负载均衡策略将请求分发到多个后端服务实例中,以实现请求的平衡和高可用性。
  3. 安全性:Gateway网关可以用作安全层,对请求进行认证和授权,确保只有经过身份验证和授权的请求才能访问后端服务。它可以集中处理身份验证、授权、API密钥管理等安全相关的功能。
  4. 监控和分析:Gateway网关能够收集和记录请求的日志信息,包括请求的响应时间、错误信息等。这些日志信息可以用于监控和分析系统的性能、故障排查等。
  5. 缓存和性能优化:Gateway网关可以缓存常用的请求响应,减少对后端服务的重复请求,从而提高系统的性能和响应速度。
  6. 灰度发布:Gateway网关支持灰度发布,可以通过路由配置和请求过滤来实现针对特定用户或特定条件的版本发布,以降低新功能引入的风险。
    1. 断路器支持:Gateway 支持断路器模式,可以在后端服务发生故障或不可用时提供故障转移和容错能力。
  7. 动态路由:Spring Cloud Gateway 提供了动态路由的功能,允许你在运行时根据需要动态地添加、删除或修改路由规则,而无需重新启动网关服务。

Gateway2.2.2官网文档

简单使用

引入依赖

gateway使用webflux进行异步非阻塞模型的实现,需要去掉boot的web依赖

<!--引入gateway网关依赖-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置

server:
  port: 8889
spring:
  application:
    name: GateWay_server
  cloud:
    consul:
      host: ekkosblog.online #注册consul服务的主机
      port: 8500 #注册consul服务的端口号
      discovery:
        #        register-health-check: false #关闭consu了服务的健康检查[不推荐]
        instance-id: ${spring.application.name}02
        service-name: ${spring.application.name} #指定注册的服务名称 默认就是应用名
        heartbeat:
          enabled: true



# 配置gateway网关相关配置
  
    gateway:
      discovery:
          locator:
            enabled: true # 开启根据服务名称获取路由,默认为true
      routes:
        # 访问http://localhost:8889/hello==>http://Hystrix-server/hello 
        - id: producer_test1                           # 指定路由唯一标识
          uri: lb://Hystrix-server # 指定路由服务的地址,通过负载均衡获取具体的服务ip和端口
          predicates:
            - Path=/hello                     # 指定路由规则
    
        
        - id: product_route
          uri: lb://Hystrix-server
          predicates:
            - Path=/producer/**

        - id: product_route2
          uri: http://21c # 不通过负载均衡
          predicates:
            - Path=/p2/**

启动类不需要任何配置,直接启动。

Gateway工作流程

路由由一个目标URI、一组谓词和一组过滤器定义。谓词用于匹配请求的各个部分,而过滤器用于对请求和响应进行处理和修改。通过配置和组合不同的路由、谓词和过滤器,可以实现复杂的请求路由和处理逻辑,以满足特定的业务需求。

Route(路由):网关的基本构建块。它由ID、目标URI、一组谓词(Predicates)和一组过滤器(Filters)组成。当所有谓词都匹配成功时,该路由将被匹配。

Predicate(谓词):它是一个基于Java 8函数式接口Predicate的实现。输入类型是Spring Framework的ServerWebExchange对象,可以用它来匹配HTTP请求的各个部分,比如头部信息或参数。

Filter(过滤器):它是Spring Framework的GatewayFilter接口的实例,通过特定的工厂进行构造。在发送下游请求之前或之后,可以在过滤器中修改请求和响应。过滤器提供了一种拦截和处理请求的机制,可以在请求经过网关时进行一些自定义操作,如鉴权、请求日志记录、请求转换等。

1684547102996.png

图片来自Gateway官网。

官方是这样描述的:

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. All “pre” filter logic is executed. Then the proxy request is made. After the proxy request is made, the “post” filter logic is run.

客户端向Spring Cloud Gateway发起请求。如果网关的Handler Mapping确定请求匹配了某个路由,该请求将被发送到网关的Web Handler。Web Handler会使得该请求通过一个特定于该请求的过滤器链。过滤器链上的过滤器逻辑被分为两部分,前半部分在代理请求发送之前执行,后半部分在代理请求发送之后执行。过滤器链上方的部分被称为"pre"过滤器逻辑,负责处理代理请求发送之前的逻辑操作。然后进行代理请求。代理请求发送完成后,过滤器链下方的部分被称为"post"过滤器逻辑,负责处理代理请求发送之后的逻辑操作。

在Spring Cloud Gateway中,Handler Mapping是用于将请求映射到相应的处理程序(Handler)的组件。它决定了请求应该被路由到哪个路由定义上。Handler Mapping会根据请求的路径、方法、头部信息等进行匹配,并选择最匹配的路由进行处理。Predicate是用于定义路由规则的一部分。它基于请求的各种属性(如路径、方法、头部信息、参数等)来进行判断和匹配。当请求到达Spring Cloud Gateway时,Handler Mapping会使用定义好的路由规则,包括谓词(Predicate)和过滤器(Filter),来决定请求应该被路由到哪个路由定义上。

Predicate

Predicate还有很多设置,具体可以查看官网。

predicates:
  - Path=/example/** #路径匹配(Path Matching)请求的路径是否以 /example/ 开头
  - Host=example.com #主机匹配(Host Matching)请求的主机是否为 example.com。
  - Method=GET #方法匹配(Method Matching) 请求的方法是否为 GET
  - Query=name, value=John #查询参数匹配(Query Parameter Matching)请求的查询参数中是否包含 name=John。
  - Header=X-Custom-Header, value=abc # 请求头匹配(Header Matching)请求的头部信息中是否包含名为 X-Custom-Header,值为 abc 的头部。
  - After=2023-05-21T10:39:33.993+08:00[Asia/Shanghai] #在这个时间之后才能访问
  - Cookie=mycookie,mycookievalue # 配置cookie

官网给出了Predicate和Filter两种配置方式:shortcuts和 fully expanded arguments. 上面这种属于shortcuts,下面是 fully expanded arguments的示例:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

Filter

内置过滤器配置

官网给出了很多的内置的过滤器

spring:
  cloud:
    gateway:
      default-filters: # 默认全局过滤器
        - AddResponseHeader=X-Response-Default-Red, Default-Blue
        - PrefixPath=/httpbin
#- AddResponseHeader=X-Response-Default-Red, Default-Blue:该过滤器将在每个响应中添加一个名为X-Response-Default-Red的响应头,并将其值设置为Default-Blue。这个过滤器会应用于所有的路由规则,无论具体的匹配条件是什么。
#- PrefixPath=/httpbin:该过滤器会在请求匹配到路由规则后,在转发请求之前,将请求的路径添加前缀/httpbin。同样,这个过滤器会应用于所有的路由规则。
​
      routes:
      - id: add_request_header_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment}
        - Host: {segment}.myhost.org
        filters:
        - AddRequestHeader=X-Request-Red, Blue-{segment} # 添加请全头,动态拼接
        - AddRequestParameter=red, blue # 添加请求参数
        - AddResponseHeader=foo, bar-{segment} #响应头 添加参数,动态拼接
        - PrefixPath=/emp       # 添加url前缀:/emp                          
        - StripPrefix=2     #去掉前缀:前2个
      

自定义过滤器配置

实现了GlobalFilter接口的过滤器将在全局范围内生效,即应用于所有的路由规则。

@Bean
public GlobalFilter customFilter() {
    return new CustomGlobalFilter();
}
​
public class CustomGlobalFilter implements GlobalFilter, Ordered {
​
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("进入自定义的filter");
        if(exchange.getRequest().getQueryParams().get("username")!=null){
            log.info("用户身份信息合法");
            Mono<Void> m=chain.filter(exchange); //放行
            //得到响应:可以从m中获取响应结果,进行处理
            return m;
        }
        log.info("非法用户,拒绝访问!!!");
       return exchange.getResponse().setComplete();
    }
​
    @Override
    public int getOrder() { //用于过滤器执行排序,可以使用@Order代替
        return -1; //越小越先执行
    }
}

负载均衡策略设置

默认策略是轮询

设置单个路由为随机

spring:
  cloud:
    gateway:
      routes:
        - id: example-route
          uri: lb://service-name?strategy=random
          predicates:
            - Path=/example

设置所有路由为响应加权

spring:
  cloud:
    gateway:
      loadbalancer:
        strategy: WeightedResponse

配置断路器

可以通过集成断路器模式来实现对服务的熔断和容错处理。常用的断路器模式实现是使用 Netflix Hystrix 库。

引入hystrix依赖

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

设置一个默认转发路径并且配置开启允许短路配置。

@SpringBootApplication
@EnableCircuitBreaker //必须添加
@RestController
public class GateWayServer08Application {
​
    public static void main(String[] args) {
        SpringApplication.run(GateWayServer08Application.class, args);
    }
​
    // 配置一个转发路径:当服务不可用时会转发到该路径
    @RequestMapping("/fallback")
    public String fallback() {
        return "Service is temporarily unavailable. Please try again later.";
    }
}

配置

spring:
  cloud:
    gateway:
      routes:
        - id: example_route
          uri: http://example.com
          predicates:
            - Path=/example/**
          filters:
            - name: Hystrix
              args:
                name: fallbackCommand #断路器的名称
                fallbackUri: forward:/fallback #指定一个回退 URI
                fallbackStatus: 200 # 响应转码
                execution.isolation.thread.timeoutInMilliseconds: 5000 
                circuitBreaker.enabled: true
                circuitBreaker.requestVolumeThreshold: 10
                circuitBreaker.sleepWindowInMilliseconds: 5000
                circuitBreaker.errorThresholdPercentage: 50

上述配置中,我们在一个示例路由上添加了 Hystrix 过滤器,并配置了相关参数:

  • name: 断路器的名称,用于识别断路器的作用。
  • fallbackUri: 指定一个回退 URI,用于处理断路器打开时的请求回退。
  • fallbackStatus: 指定回退请求的 HTTP 状态码。
  • execution.isolation.thread.timeoutInMilliseconds: 设置断路器的超时时间,单位为毫秒。
  • circuitBreaker.enabled: 是否启用断路器。
  • circuitBreaker.requestVolumeThreshold: 触发断路器打开的请求阈值。
  • circuitBreaker.sleepWindowInMilliseconds: 断路器打开后的等待时间窗口,之后会尝试半开状态。
  • circuitBreaker.errorThresholdPercentage: 断路器打开的错误阈值百分比。

整合springsecurity

在网关中完成认证授权

引入security依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

配置springsecurity

Spring Cloud Gateway 默认使用 Netty 服务器作为其底层服务器。Netty 是一个高性能的异步事件驱动的网络应用程序框架,专门用于快速开发可扩展的服务器和网络应用程序。 和在使用tomcat服务器中的配置略有差异。

@Configuration 
@EnableWebFluxSecurity //允许配置 必须开启
public class config {
    @Bean
    public MapReactiveUserDetailsService userDetailsService() {
        //自定义一个用户
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .roles("ADMIN")
                .build();
​
        return new MapReactiveUserDetailsService(user);
    }
​
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authenticated()
                .and()
                .httpBasic().and()
                .formLogin();
        return http.build();
    }
}