Gateway组件

SpringCloud:Gateway组件

一、什么是网关

Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:身份认证和权限校验、服务路由和负载均衡、请求限流等功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5C6CpPo-1635933582867)(F:\md上传的图片\image-20211103133359635.png)]

所有想要访问接口的客户端、用户等都先将请求发至网关,再由网关来解决将该请求交给哪个服务进行处理。

二、工作原理

客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。该处理程序通过特定于请求的过滤器链运行请求。筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑。所有“前置”过滤器逻辑均被执行。然后发出代理请求。发出代理请求后,将运行“后”过滤器逻辑。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFEoxIPl-1635933582869)(F:\md上传的图片\image-20211103133943652.png)]

简而言之:客户端发起请求->由Predicate里面所定义的规则选去合适的路由->网关处理程序执行Filter(前置)->转发请求并执行过滤器(后置)

三、gateway的三大概念

  • Route 路由:gateway的基本构建模块。它由ID、目标URI、断言集合和过滤器集合组成。如果聚合断言结果为真,则匹配到该路由。
  • Predicate 断言:Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等
  • Filter 过滤器:一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理

四、案例在这里插入图片描述

client:feign接口
demo:消费者
gateway-gateway:网关
gateway-service:提供者
<!--引入gateway 网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

Goods

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {
    private int id;
    private String title;
    //商品标题
    private double price;
    //商品价格
    private int count;
    //商品库存
}

client

@FeignClient(value = "gateway-service")
public interface GoodsFeignClient {

    @GetMapping("/gateway-service/goods/findOne/{id}")
    Goods findOne(@PathVariable("id") int id);
}

demo

@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private GoodsFeignClient goodsFeignClient;

    @GetMapping("/goods/{id}")
    public Goods findOne(@PathVariable("id") int id){
        return goodsFeignClient.findOne(id);
    }
}
spring:
  application:
    name: demo

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

server:
  port: 8003
  servlet:
    context-path: /${spring.application.name}

service

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @GetMapping("/findOne/{id}")
    public Goods findOne(@PathVariable("id") int id){
        Goods goods = new Goods(id, "华为手机", 3999, 10000);
        return goods;
    }
}
spring:
  application:
    name: gateway-service

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

server:
  port: 8002
  servlet:
    context-path: /${spring.application.name}

gateway

spring:
  application:
    name: gateway-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: #集合。
        # id: 唯一标识。默认是一个UUID
        # uri: 转发路径
        # predicates: 条件,用于请求网关路径的匹配规则
        - id: demo
          # 静态路由
          #uri: http://localhost:8003
          # 动态路由
          uri: lb://demo 
          predicates:
            - Path=/demo/order/**
#            - Path=/**
        - id: gateway-service
          uri: lb://gateway-service
          predicates:
            - Path=/gateway-service/goods/**
      discovery:
        locator:
          enabled: true #开启动态路由 从微服务中获取服务名
          lower-case-service-id: true  #允许小写

server:
  port: 8000
  servlet:
    context-path: /${spring.application.name}

网关的路由配置总共需要配置三项
1、id是该路由的唯一标识,
2、uri指定的是需要路由到的服务地址,
3、predicates表示断言,如果满足断言的要求,则网关便会将请求交给uri指定的服务. 

静态路由和动态路由区别
静态路由:将uri 写死
动态路由:lb://服务名称

lb:// 表示将请求负载均衡到 demo 服务。断言的形式有很多,比如这里使用的Path,它是用来判断请求路径的,当请求路径以/demo/order开头,该请求就会被这一网关配置处理。
  • 注意:使用path 去判断路径会出现找不到服务,这时候需要去看看是否有添加项目路径在配置文件中。此处多尝试一下。

测试

请求路径(get)
localhost:8000/demo/order/goods/1
返回参数
{
    "id": 1,
    "title": "华为手机",
    "price": 3999.0,
    "count": 10000
}

五、路由配置

在刚刚的例子中,我们使用到了一个路径的路由断言,只需要在-Path中配置/demo/order/**,那么以/demo/order/开头的请求就会被网关处理,这是如何实现的呢?事实上,Gateway中有很多的路由断言工厂,当我们在配置文件中对断言进行配置后,这些配置就会被路由断言工厂进行解析并处理,而-Path配置就是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory来处理的。SpringCloud Gateway中一共提供了11种基本的路由断言工厂,分别如下:
1.BeforeRoutePredicateFactory:判断是否为某个时间点之前的请求
2.AfterRoutePredicateFactory:判断是否为某个时间点之后的请求
3.BetweenRoutePredicateFactory:判断是否为某两个时间点之间的请求
4.CookieRoutePredicateFactory:判断是否包含某些cookie
5.HeaderRoutePredicateFactory:判断是否包含某些header
6.HostRoutePredicateFactory:判断请求是否是访问某个host
7.MethodRoutePredicateFactory:判断请求方式是否是指定的方式
8.PathRoutePredicateFactory:判断请求路径是否满足规则
9.QueryRoutePredicateFactory:判断请求参数是否包含指定的参数
10.RemoteAddrRoutePredicateFactory:判断请求ip是否在指定的范围内
11.WeightRoutePredicateFactory:权重处理
5.1、通过After匹配

After Route Predicate Factory采用一个参数——日期时间。在该日期时间之后发生的请求都将被匹配。

spring:
  cloud:
    gateway:
      routes:
       - id: time_route
        uri: http://time.demo
        predicates:
         - After=2021-11-03T06:06:06+08:00[Asia/Shanghai]
5.2、通过Before匹配

Before Route Predicate Factory采用一个参数——日期时间。在该日期时间之前发生的请求都将被匹配。

spring:
  cloud:
    gateway:
      routes:
       - id: time_route
        uri: http://time.demo
        predicates:
         - Before=2021-11-03T06:06:06+08:00[Asia/Shanghai]
5.3、通过Between匹配

Between 路由断言 Factory有两个参数,datetime1和datetime2。在datetime1和datetime2之间的请求将被匹配。datetime2参数的实际时间必须在datetime1之后。

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: http://example.org
        predicates:
        - Between=2021-11-01T06:06:06+08:00[Asia/Shanghai], 2021-11-06T06:06:06+08:00[Asia/Shanghai]
5.4、通过Cookie匹配

Cookie 路由断言 Factory有两个参数,cookie名称和正则表达式。请求包含次cookie名称且正则表达式为真的将会被匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p
5.5、通过Header匹配

Header 路由断言 Factory有两个参数,header名称和正则表达式。请求包含次header名称且正则表达式为真的将会被匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Header=X-Request-Id, \d+
5.6、通过Host匹配

Host 路由断言 Factory包括一个参数:host name列表。使用Ant路径匹配规则,.作为分隔符。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org
5.7、通过Method匹配

Method 路由断言 Factory只包含一个参数: 需要匹配的HTTP请求方式

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Method=GET #所有get请求都被路由
5.8、通过Path匹配

Path 路由断言 Factory 有2个参数: 一个SpringPathMatcher表达式列表和可选matchOptionalTrailingSeparator标识 .

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment} #请求路径符合要求,则此路由将匹配,例如:/foo/1 或者 /foo/bar
5.9、通过Query匹配

Query 路由断言 Factory 有2个参数: 必选项param和可选项regexp.

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Query=baz #则包含了请求参数baz的都将被匹配。
        - Query=foo, ba. # 如果请求参数里包含foo参数,并且值匹配为ba.表达式,则将会被路由,如:bar and baz
5.10、通过RemoteAddr匹配

RemoteAddr 路由断言 Factory的参数为 一个CIDR符号(IPv4或IPv6)字符串的列表,最小值为1,例如192.168.0.1/16(其中192.168.0.1是IP地址并且16是子网掩码)。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24 #如果请求的remote address 为 192.168.1.10则将被路由

多个Predicates同时存在于同一个路由时,请求必须同时满足所有的条件才会被这个路由匹配。

六、Gateway过滤器

1、概述

在路由的配置中,我们还可以配置一项filter,它是Gateway提供的过滤器,可以对进入网关的请求和返回的响应进行相应的处理。与路由断言类似,Gateway同样提供了过滤器工厂。官网上又两大类过滤器,加起来三十多种。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uyZvaykP-1635933582872)(F:\md上传的图片\image-20211103162405684.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MTwN341s-1635933582874)(F:\md上传的图片\image-20211103162253681.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yC6fUT48-1635933582874)(F:\md上传的图片\image-20211103162456221.png)]

2、局部过滤器

  • 比如第一个AddRequestHeader GatewayFilterFactory,从名字就能够看出来,这是用来添加请求头信息的,具体配置方式如下:
spring:
  cloud:
    gateway:
      routes:
      - id: demo
        uri: lb://demo
        predicates: 
        - Path=/demo/order/**
        filters:
         - AddRequestParameter=username,zhangsan #修改接口发现测试成功

3、全局过滤器

  • 为了更加灵活地适应各种场景,Gateway还提供了一种特殊的过滤器—GlobalFiler(全局过滤器),它的作用与default-filter类似,区别在于GlobalFilter需要我们自己去实现,要做的就是实现GlobalFilter接口。
@Order(0) //数值越小 越先执行
@Component
public class MyFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定义全局过滤器执行了~~~");
        return chain.filter(exchange);//放行
    }
}
案例
@Order(0)
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisTemplate redisTemplate ;

    /**
     *
     * @param exchange  网关与web环境交换机
     * @param chain  过滤器链
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        String method = request.getMethodValue();
        String path = request.getURI().getPath();

        //登陆请求直接放行
        if(method.equalsIgnoreCase("post") && path.endsWith("/user")){
            return chain.filter(exchange);
        }

        //获取请求中携带的token数据
        List<String> headers = request.getHeaders().get("token");

        //用户未携带token , 直接返回错误信息给客户端
        if(headers==null || headers.size()<=0){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        //获取客户端发送的token
        String token = headers.get(0);
        //判断token是否存在 , 如果不存在说明未登录,或者登陆状态过期
        Boolean flag = redisTemplate.hasKey(token);
        if(!flag){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        //放行 , 访问资源
        return chain.filter(exchange);
    }

七、处理跨域

1、概念
跨域问题是指浏览器禁止请求的发起者与服务端发生跨域的ajax请求。

跨域是每一个前后端分离项目都需要面临的问题,但有了网关,我们就可以将处理跨域的流程写在网关里,无需在每一个微服务中都进行配置了。
2、配置
浏览器在向服务器发起请求之前,会先发送一个option请求进行询问,查看是否满足要求,为了防止这个询问请求被拦截,所以需要配置 `add-to-simple-url-handler-mapping: true` ; `[/**]` 表示对所有的请求进行处理; `maxAge: 360000` 用于配置跨域检测的有效时间,当浏览器发送了一次option请求进行询问并且成功后,在这段有效时间内,服务器将不再要求对浏览器发送过来的请求进行检测,由此提高了性能。
spring:
  cloud:
    gateway:
      globalcors: # 全局跨域处理
        add-to-simple-url-handler-mapping: true # 解决options询问请求被拦截的问题
        cors-configurations:
          '[/**]':
            allowedOrigins: # 配置允许哪些网站跨域 通常用 "*" 表示
              - "http://localhost:8000"
              - "http://localhost:9000"
            allowedMethods: # 配置允许哪些请求方式跨域
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 允许请求携带Cookie
            maxAge: 360000 # 跨域检测的有效时间

解决options询问请求被拦截的问题

       cors-configurations:
         '[/**]':
           allowedOrigins: # 配置允许哪些网站跨域 通常用 "*" 表示
             - "http://localhost:8000"
             - "http://localhost:9000"
           allowedMethods: # 配置允许哪些请求方式跨域
             - "GET"
             - "POST"
             - "DELETE"
             - "PUT"
             - "OPTIONS"
           allowedHeaders: "*" # 允许在请求中携带的头信息
           allowCredentials: true # 允许请求携带Cookie
           maxAge: 360000 # 跨域检测的有效时间
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值