统一网关Gateway

  • 为什么需要网关

    • 网关的功能:
      1. 身份认证和权限校验
      2. 服务路由、负载均衡
      3. 请求限流

    请添加图片描述

  • 网关的技术实现

    • 在SpringCloud中网关的实现包括两种:
      1. gateway
      2. zuul
    • Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

搭建网关服务

  • 步骤

    1.创建项目,引入nacos服务发现和gateway依赖

    2.配置application.yml,包括服务基本信息、nacos地址、路由

    路由配置包括:

    1.路由id:路由的唯一标示

    2.路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡

    3.路由断言(predicates):判断路由的规则,

    4.路由过滤器(filters):对请求或响应做处理

  • 创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!--网关依赖-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!--nacos服务发现依赖-->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
  • 编写路由配置及nacos地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    server:
    port: 10010

    spring:
    application:
    name: gateway
    cloud:
    nacos:
    server-addr: localhost:8848
    gateway:
    routes:
    - id: user-service #路由标记,必须唯一
    uri: lb://userservice #路由的目标地址
    predicates: # 路由断言,判断路径是否符合规则
    - Path=/user/** # 路由断言,判断路径是否是一/user开头,如果是则符合
    - id: order-service
    uri: lb://orderservice
    predicates:
    - Path=/order/**
  • 作用

    请添加图片描述

路由断言工厂Route Predicate Factory

路由过滤器 GatewayFilter

  • GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:

    请添加图片描述

  • 过滤器工厂GatewayFilterFactory

    请添加图片描述

    • 例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!

    #实现方式:在gateway中修改application.yml文件,给userservice的路由添加过滤器:

    spring:
    cloud:
    gateway:
    routes: # 网关路由配置
    - id: user-service
    uri: lb://userservice
    predicates:
    - Path=/user/**
    filters: # 过滤器
    - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

    #如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
    spring:
    application:
    name: gateway # 服务名称
    cloud:
    nacos:
    server-addr: localhost:8848 # nacos地址
    gateway:
    routes: # 网关路由配置
    - id: user-service
    uri: lb://userservice
    predicates:
    - Path=/user/**
    - id: order-service
    uri: lb://orderservice
    predicates:
    - Path=/order/**
    default-filters: # 默认过滤器,会对所有的路由请求都生效
    - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

  • 全局过滤器 GlobalFilter

    全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。

    区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。

    定义方式是实现GlobalFilter接口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public interface GlobalFilter {
    /**
    * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
    *
    * @param exchange 请求上下文,里面可以获取Request、Response等信息
    * @param chain 用来把请求委托给下一个过滤器
    * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
    */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
    }
    • 定义全局过滤器,拦截并判断用户身份

      需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

      • 参数中是否有authorization,

      • authorization参数值是否为admin

      如果同时满足则放行,否则拦截

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Order(-1)
    @Component
    public class AuthorizeFilter implements GlobalFilter {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    //1.获取请求参数
    ServerHttpRequest request = exchange.getRequest();
    MultiValueMap<String, String> params = request.getQueryParams();
    //2.获取参数中的authorization 参数
    String auth = params.getFirst("authorization");
    //3.判断参数数值是否相等
    if ("admin".equals(auth)) {
    return chain.filter(exchange);
    }
    //5.否,拦截
    //5.1.设置状态码
    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
    //5.2.拦截请求
    return exchange.getResponse().setComplete();
    }
    }