【SpringCloud】10. 服务网关

300 阅读4分钟

定义

网关统一服务入口,可方便实现对平台众多服务接口进行管控,对访问服务的身份认证、防报文重放与防数据篡改、功能调用的业务鉴权、响应数据的脱敏、流量与并发控制,甚至基于API调用的计量或者计费等等。

作用

  • 路由转发:接收一切外界请求,转发到后端的微服务上去。
  • 过滤器:在服务网关中可以完成一系列的横切功能,例如权限校验、限流以及监控等。

为什么需要网关?

  1. 网关可以实现服务的统一管理。
  2. 网关可以解决微服务中通用代码的冗余问题(如权限控制,流量监控,限流等)。

网关在微服务中的架构

Gateway组件

1. 说明

这个项目提供了一个在Spring MVC之上构建API网关的库。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为API提供横切关注点。比如:安全性、监控/度量和弹性。

2. 特性

  • 基于Spring Boot 2.x,Spring WebFlux和Reactor构建
  • 响应式异步非阻塞IO模型
  • 动态路由
  • 请求过滤

Gateway动态路由开发

在Gateway中,可以使用配置文件或者配置类来配置动态路由。由于Spring Cloud官方推荐使用配置文件的方式配置动态路由,所以本文不再讲述使用配置类配置动态路由的方式。

1. 配置网关定向访问

  1. 创建独立的gateway模块。

  2. 将模块注册入服务注册中心(本文以Consul为注册中心)。

  3. 模块引入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>   
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    
  4. 模块编写网关配置

    spring:
      application:
        name: gateway
      cloud:
        # consul配置
        consul:
          ...
        # gateway配置
        gateway:
          routes:
            # 路由唯一标识
            - id: product_route
              # 路由访问地址
              uri: http://localhost:9001/
              # 路由匹配规则
              predicates:
                - Path=/product/**
            - id: user_route
              uri: http://localhost:9002/
              predicates:
                - Path=/user/**
    
  5. 通过访问 http://网关ip:网关port/Path ,网关会根据配置文件自动跳转到 uri/Path,从而访问不同服务中的接口。

注意:

  1. 当引入spring-cloud-starter-gateway依赖时,同时引入spring-boot-starter-web依赖,那么项目会启动失败。因为Gateway是基于Spring WebFlux开发的,而Spring WebFlux底层封装了Spring MVC。如果同时引入两个依赖,那么会导致冲突。所以在使用Gateway组件时,必须移除spring-boot-starter-web依赖。

  2. gateway服务不引入common服务。因为common服务中配置了spring-boot-starter-web依赖,所以还需要手动配置consul等。

  3. 在配置路由中

    predicates:
      - Path=/product/**
    

    这种配置为yml文件中集合(字符串数据)配置方式,原型为

    predicates: [Path=/product/**]
    

    这里的**代表多级路径匹配。

  4. 在配置路由中

    routes:
      - id: product_route
        uri: http://localhost:9001/
        predicates:
          - Path=/product/**
      - id: user_route
        uri: http://localhost:9002/
        predicates:
          - Path=/user/**
    

    这种配置为yml文件中集合(对象数据)配置方式,原型为

    routes: [
    	{
                 id: product_route,
                 uri: http://localhost:9001/,
                 predicates: [Path=/product/**]
    	}, 
    	{
                 id: user_route,
                 uri: http://localhost:9002/,
                 predicates: [Path=/user/**]
    	}
    ]
    

2. 配置网关负载均衡访问

  1. 创建gateway模块,注册,引入依赖。

  2. 网关配置

    spring:
      application:
        name: gateway
      cloud:
        # consul配置
        consul:
          host: localhost
          port: 8500
          discovery:
            service-name: ${spring.application.name}
        # gateway配置
        gateway:
          routes:
            - id: product_route
              uri: lb://products
              predicates:
                - Path=/product/**
            - id: user_route
              uri: lb://users
              predicates:
                - Path=/user/**
          discovery:
            # 开启根据服务名动态获取路由
            locator:
              enabled: true
    

注意:

  1. 在配置网关中

    uri: lb://products
    

    lb:网关使用负载均衡策略进行服务访问。

    products:表示注册中心具体服务名。

解决Gateway跨域问题

在前后端分离的项目中,如果原先使用的是nginx做反向代理和负载均衡,那么只把nginx停掉和按照上述步骤配置gateway会产生跨域问题。

因为Gateway使用的是webflux,而不是springmvc,所以后端原本配置的@CrossOrigin已经解决不了跨域问题了。需要先关闭webflux的cors,再从gateway的filter里边配置cors即可。

  1. 在前端将nginx地址改为gateway地址

    image.png

  2. 去掉后端所有controller上的@CrossOrigin注解

    image.png

  3. 配置Gateway服务中的application.yml

    spring:
      application:
        name: afterlives-gateway
      cloud:
      	# consul配置
        consul:
          ...
        # gateway配置
        gateway:
          routes:
           ...
          discovery:
           ...
          # 配置跨域
          globalcors:
            corsConfigurations:
              '[/**]':
                allowedHeaders: "*"
                allowedOrigins: "*"
                allowedMethods:
                  - GET
                    POST
                    DELETE
                    PUT
                    OPTION
    
  4. 在Gateway服务中创建config包,创建CorsConfig类

    // gateway跨域
    @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);
        }
    }
    

查看网关路由规则列表

Gateway提供路由访问规则列表的web界面,但是默认是关闭的。如果想要查看服务路由规则可以在配置文件中开启。

  1. 网关模块开启所有web端点(其中包括Gateway暴露的端点)

    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  2. 如果注册中心使用的是Nacos,则还需在Gateway中添加如下配置

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  3. 访问路由管理列表地址:http://网关ip:网关port/actuator/gateway/routes