Gateway的简单使用

SpringCloud Gateway

是什么?

Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。

是所有微服务访问的统一入口

网关由来.png

图片来源自网络

做什么的

Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等

网关作用.png

图片来源自网络

为什么要用

SpringCloud官方出品 方便使用,Zuul2 并没有整合进SrpingCloud中

特征

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
  • 动态路由
  • Predicates 和 Filters 作用于特定路由
  • 集成 Spring Cloud DiscoveryClient
  • 易于编写的 Predicates 和 Filters
  • 限流
  • 路径重写
  • 集成断路器hystrix(gateway3.0+已经删除)

关键名词及作用

  • 路由:网关的基本构建组成,它由ID,目标URL,谓词集合和过滤器定义,如果聚合谓词为true,则匹配路由;

  • 谓词:符合Predicate的条件,就使用该路由的配置,否则就不管,Predicate是Java 8提供的一个函数式编程接口。

  • 过滤器:用于发送和返回请求之前,修改请求和响应

关于过滤器

过滤器分为“pre”和“post”两种方式

  • pre:在请求被路由之前调用,可以做参数校验、权限校验、流量监控、日志输出、协议转换等

  • post:在路由到微服务以后执行,可以做响应内容、响应头的修改,日志的输出,流量监控等

Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种GatewayFilter(局部过滤器) 与 GlobalFilter(全局过滤器)。

  • GatewayFilter :应用到单个路由或者一个分组的路由上。

  • GlobalFilter :应用到所有的路由上。

全局过滤器.png

图片来源自网络

开始使用

该文章使用3.0+版本

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
复制代码

不要导入web依赖(下面的依赖),gateway的starter中已经引入了spring-boot-starter-webflux依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
复制代码

否则启动项目时会出现 Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway。(在类路径上发现Spring MVC,它与Spring Cloud Gateway不兼容。)

谓词使用

网关谓词及作用.png

Cookie 路由谓词工厂
server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: cookie_route 
          uri: http://www.baidu.com   需要跳转的地址
          predicates: 
            - Cookie=ityouknow, kee.e 
复制代码

postman调用截图

cookie谓词调用结果.png

图片来源自网络


请求头路由谓词工厂
server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: head_route
          uri: http://www.baidu.com
          predicates:
            - Header=head, \d+   # \d+ 只能是数字 + 号表示至少出现一次
复制代码

postman调用截图

请求头谓词调用结果.png

path路由谓词工厂

另起一个端口为8087的服务

@RestController
@RequestMapping("/tool")
public class ToolController {

    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
}
复制代码

配置信息

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: path_route
          uri: http://localhost:8087
          predicates:
            - Path=/tool/** # 只要包含tool就会匹配上
#            - Path=/tool/{segment}  包含tool再往后匹配一个 斜杠区间  比如      localhost:9000/tool/hello  能匹配上  localhost:9000/tool/hello/v1 不能匹配上(修改8087项目方法地址为/hello/v1再做测试)
复制代码

postman调用

postman请求 localhost:9000/tool/hello

返回hello


请求参数路由谓词工厂

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: query_route
          uri: http://localhost:8087
          predicates:
            - Query=val,0?(13|14|15|17|18|19)[0-9]{9} 
#    - Query=val 匹配参数中包含val的请求 
#    - Query=val,0?(13|14|15|17|18|19)[0-9]{9}  匹配参数中包含val,并且参数值需要符合逗号后面的正则表达式 的请求,
#      该表达式是手机号的正则,测试时可以试试其他的,正则表达式总长度不能大于50,否则会报错
复制代码

修改代码

@RestController
@RequestMapping("/tool")
public class ToolController {

    @GetMapping("/hello")
    public String hello(String val){
        return val;
    }
}
复制代码

postman调用

postman请求 localhost:9000/tool/hello?val=1531xxxxxxx 返回参数的值


以上就是常用谓词的简单用例了

过滤器使用

1、添加请求头过滤器工厂 AddRequestHeader GatewayFilter factory

添加接口

@RestController
@RequestMapping("request")
public class RequestController {

    @GetMapping("head")
    public void getHead(HttpServletRequest request){
        System.out.println(request.getHeader("X-Request-Tool"));
    }

}
复制代码

添加过滤器配置

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: add_header_route
          uri: http://localhost:8087
          predicates:
            - Path=/request/**
          filters:
            - AddRequestHeader=X-Request-Tool, Box
复制代码

访问 localhost:9000/request/head

服务端打印结果

请求头过滤器调用结果.png


2、删除请求头过滤器工厂 RemoveRequestHeader

添加过滤器配置

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: rm_header_route
          uri: http://localhost:8087
          predicates:
            - Path=/request/**
          filters:
            - RemoveRequestHeader=X-Request-Tool
复制代码

postman请求截图

删除请求头过滤器-请求.png

服务端打印结果

image.png

3、添加参数工厂

添加接口

@GetMapping("parameter")
public void getParameter(HttpServletRequest request){
    System.out.println(request.getParameter("red"));
}
复制代码

修改配置信息

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: parameter_route
          uri: http://localhost:8087
          predicates:
            - Path=/request/**
          filters:
            - AddRequestParameter=red, blue
            # 添加 名为red,值为bule 的参数
复制代码

请求 localhost:9000/request/parameter

控制台打印结果

image-20211027142911632.png


过滤器工厂基本使用就列举这三个,其他的可以去SpringCloud Gateway官网查看。

4、自定义过滤器的实现

1)全局过滤器的自定义实现 GlobalFilter

直接实现 GlobalFilter接口即可,不用添加任何配置,直接作用在所有请求,所有路由

@Component
public class LoginFilter implements GlobalFilter, Ordered {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求头中的token 如果没有则直接结束
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if(ObjectUtils.isEmpty(token)){
            // 3.如果不存在 : 认证失败
            System.out.println("没有登录");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete(); // 请求结束
        }
        // 4.如果存在,继续执行
        return chain.filter(exchange); // 继续向下执行
    }

    @Override
    public int getOrder() {
        // 优先级 数值越大执行越靠后
        return 100;
    }
}
复制代码

postman调用截图

image-20211027170204633.png image-20211027170147366.png

2) 局部过滤器 GatewayFilter

继承AbstractGatewayFilterFactory,需要配置作用的某个(/a/b)或者某类(/a/*)路由信息

提醒:

          predicates:
            - Path=/**/**
          ##  这样的配置信息会在启动项目时报错
复制代码

实现代码

@Component
public class TogetherFilter extends AbstractGatewayFilterFactory {

    @Override
    public GatewayFilter apply(Object config) {
        String name = "";
        return (exchange,chain) -> {
            //获取URI
            URI newUri = exchange.getRequest().getURI();
            String rawPath = newUri.getRawPath();
            System.out.println(rawPath);

            rawPath = rawPath + "/url";
            //修改URI
            ServerHttpRequest build = exchange.getRequest().mutate().path(rawPath).build();

            return chain.filter(exchange.mutate().request(build).build());
        };
    }
}
复制代码

将自定义的过滤器配置到yml中

server:
  port: 9000 # 指定网关服务的端口
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: together_route
          uri: http://localhost:8087
          predicates:
            - Path=/request
          filters:
            - TogetherFilter
复制代码

添加接口

@GetMapping("url")
public String getUrl(HttpServletRequest request){
    return request.getRequestURI();
}
复制代码

postman请求结果

image-20211027173631215.png

如果需要多个过滤器取满足多组路由信息,需要在yml中配置多个

   routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: cookie_route1
          uri: http://localhost:8087
          predicates:
            - Path=/tool
          filters:
            - LogFilter2
------------------------------------
        - id: cookie_route2
          uri: http://localhost:8087
          predicates:
            - Path=/request
          filters:
            - LogFilter3
复制代码

完!

猜你喜欢

转载自juejin.im/post/7036624100017569806