概述

什么是网关?为什么需要网关?

什么是网关: 网关就是架设在前端浏览器和后端微服务之间的一层服务,用于转发请求,微服务的接口不再暴露给前端页面,前端只了解网关的地址.

为什么需要网关: 其实不要也可以,加了网关就是可以做一些服务限流,统计比较方便,安全方面可能也有考虑,不会将后台服务器直接暴露.主要还是方便,前端请求只往网关上发,网关做请求和后端服务器的映射关系

GateWay实现网关 (spring cloud 2.0)

概念

GateWay提供一种简单而有效的方式来对API进行路由,以及提供一些强大的功能,例如 熔断,限流,重试
基于 WebFlux 框架实现, WebFlux 底层基于高性能通行框架 Netty

Route(路由)

路由是构建网关的基本模块, 由 ID 目标 URI 一系列的 断言过滤器 组成,如果断言为 true ,则匹配该路由

工作流程

gateway这几个概念的工作流程

  1. 设置若干个路由,路由中包括断言URI
  2. 请求过来的时候判断每个路由的断言 如果为true,则表示该路由生效
  3. 该路由中的过滤器再进行生效
  4. 注意,如果断言重复,只会匹配第一个
    在这里插入图片描述

搭建

  1. 引入pom文件
    gateway 不能引入 spring-boot-starter-web 依赖
       <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-gateway</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       </dependency>
   </dependencies>
  1. 添加yml 文件
server:
 port: 9527

spring:
 application:
   name: gateway
 cloud:
   gateway:
     routes:
         # 路由的id,没有固定规则但是要求唯一
       - id: provider-01
         # 匹配后提供服务的路由地址  
         uri: http://localhost:9001
         # 断言,路径匹配的进行路由
         predicates:
           - Path=/test01/**

       - id: provider-01-01
         uri: http://localhost:9001
         predicates:
           - Path=/future/**

       - id: provider-02
         uri: http://localhost:9002
         predicates:
           - Path=/test02/**
eureka:
 client:
   #    是否要自己注册到EUREKA 上
   register-with-eureka: true
   #    不需要去服务注册中心获取其他服务地址
   fetch-registry: true
   service-url:
     defaultZone:  http://EUREKA01:7001/eureka/

动态路由

刚才的案例中,直接指定了 服务的ip和端口,没有办法做到负载均衡和动态扩容
修改路由里面uri 改为 uri: lb://+微服务名称 即可实现负载均衡

Predicate(断言)

就是一个返回true 和 false 的东西, 返回true 就匹配.
GateWay 启动的时候打印了一堆断言类
在这里插入图片描述
我们已经用过 Path 断言,用于匹配url,接下来看看其他的断言如何使用

  1. After 请求的时间必须在指定时间之后,时间格式可以使用 ZonedDateTime.now()获得
  2. Between 就是两个时间区域之间生效,用逗号隔开
  3. Cookie 需要两个参数,一个是 cookie name 一个是正则表达式
  4. Header 和 Cookie 差不多,一个写头名称,一个正则
        - id: provider-01
          # 匹配后提供服务的路由地址
#          uri: http://localhost:9001
          uri: lb://provider-01
          # 断言,路径匹配的进行路由
          predicates:
#            根据路径匹配
            - Path=/future/test999/**
#            根据请求时间匹配
            - After=2020-09-12T13:10:07.398+08:00[Asia/Shanghai]
#            请求中必须符合cookie正则,可以多个
            - Cookie=username, tom

            - Cookie=age, 18
#             请求中头信息必须符合正则
            - Header=userId, 992

注意!

两个不同的路由指向同一个资源, 路由的断言不同, A路由的断言返回false ,B路由的断言返回true ,请求还是可以通过 B路由访问到
在这里插入图片描述

Filter(过滤)

spring框架中 GateWayFilter 实例,使用过滤器,可以在请求在路由请求前后修改

  1. AddRequestHeader 添加请求头, key value 用逗号隔开
  2. StripPrefix 去除前缀,个人感觉比较有用,用于做微服务前缀区分
    还有很多,官网上有
    链接: GateWay官方文档.
自定义过滤器

作用: 日志记录,如果在微服务层的 controller 做aop拦截记录日志,会记录下很多因为前端一个操作而微服务之间相互调用的多次无意义的请求.直接在网关层拦截请求记录

  1. 实现 GlobalFilter 和 Ordered 接口
@Component
public class MyLogFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
            String key = entry.getKey();
            List<String> value = entry.getValue();
            System.out.println("key-----"+key);
            System.out.println("value------"+value);
        }

        String name = queryParams.getFirst("name");
        if (name == null){
            // 不放行
            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
            return exchange.getResponse().setComplete();
        }
//        放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

暂时只能获取geturl中的参数,请求体里面的内容获取需要掌握 MONO相关技术才能了解.搁置一下,

todo gateway获取请求体中内容,实现日志记录功能

总结

实际开发中,众多微服务之间,可能会有 url重复的情况,前后端定义接口的时候,前端发送的请求应该添加一个微服务的前缀作为标示,到了网关根据前缀判断属于哪个微服务进行转发
其中zuul 可以直接实现前缀和微服务的映射

zuul:
  routes:
#    eureka 中服务id
    provider-01:
#      什么路径会映射到这个id上
      path: /kkk/**

当前端发送请求 http://localhost:9527/kkk/test01 的时候,zuul转发到provider-01这个微服务的请求已经变成 http://provider-01:port/test01 了,比较方便.

如果是GateWay 就需要用到filter的 StripPrefix 接受一个非0数,表示去除的前缀的个数.

	routes:
          # 路由的id,没有固定规则但是要求唯一
        - id: provider-01
          # 匹配后提供服务的路由地址
          uri: lb://provider-01
          # 断言,路径匹配的进行路由
          predicates:
#            根据路径匹配
            - Path=/provider01/**
          filters:
            - StripPrefix=1

官网上经常用{segment}来当demo,不知道什么意思,直接用 **即可.
前端用provider01前缀的请求全部都会转发到 provider-01的微服务上

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐