Spring Cloud之服务网关 Gateway

前言

API 网关的定义
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。

API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。

Gateway提供了一个用于在Spring MVC之上构建API网关的库。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注,例如:安全性,监视/度量和弹性。

Spring Cloud Gateway是spring Cloud d的一个全新的项目 ,Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

一、Gateway的特性

gateway之所以性能好,因为底层使用WebFlux,而webFlux底层使用netty通信(NIO)
动态路由:能够匹配任何请求属性;
集成Hystrix的短路器功能;
集成Spring Cloud 服务发现功能;
可以对路由指定Predicate(断言)和Filter(过滤器);

二、GateWay与zuul的区别

在SpringCloud F版之前,推荐的网关是Netflix的Zuu:

  1. Zuul 1.x 是一个基于阻塞的 I/O Api Gateway;
  2. Zuul 1.x 基于Servlet 2.5使用阻塞架构它不支持任何长链接(如WebSocket),Zuul的设计模式和Nginx比较像,每次I/O都是从工作线程中选择一个去执行,请求线程被阻塞到工作线程完成,但是差别是Nginx基于C++实现,Zuul是使用java实现的,而JVM本身会有第一次加载比较慢的情况,使得Zuul的性能比较差。
  3. Zuul 2.x 的理念比较先进,想基于Netty非阻塞和长连接,但是spring Cloud暂时还没有整合,Zuul 2.x相较于Zuul 1.x 性能有较大提升。 但是在性能方面,根据官方测试,Spring Cloud Gateway的Rps(美妙请求数)是Zuul的1.6倍。
  4. Spring Cloud Gateway建立在spring Framework 5、Project Reactor和Spring boot 2.0以上。使用非阻塞Api。同时还支持WebSocket

三、GateWay的一些重要概念

在这里插入图片描述

四、案例

说白了 Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理,接下来我们接下 Spring Cloud GateWay 内置几种 Predicate 的使用。

通过请求路径匹配
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      #开启从注册中心动态创建路由功能,利用微服务进行路由
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_route1
          uri: lb://cloud-payment-service
          predicates:
            -  Path=/get/**

各字段含义如下:

  • id:我们自定义的路由 ID,保持唯一
  • uri:目标服务地址 ,开启从注册中心动态创建路由功能,利用微服务进行路由之后可以使用lb://cloud-payment-service进行负载均衡
  • predicates:路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。

这里我们准备四个项目:
7001:位eureka的注册中心
8001/8002:提供接口的微服务 cloud-payment-service
9527:Gateway网关

在这里插入图片描述
7001,8001,8002不多介绍了https://blog.csdn.net/flycp/article/details/108432834可以异步之前的博客看一下:
我们着重说一下,cloud-gateway9527这个网关项目:
pom.xml: 引入Eureka以及Gateway相关依赖

 <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

application.yml: 这里我们直接演示集群版本通过微服务进行路由,并进行负载均衡
单机版discovery.locator.enabled: false 设置 uri: http://localhost:8001即可

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      #开启从注册中心动态创建路由功能,利用微服务进行路由
      discovery:
        locator:
          enabled: true
      routes:
        - id: payment_route1
          uri: lb://cloud-payment-service
          predicates:
            -  Path=/get/**


eureka:
  instance:
    hostname: cloud-gateway-service #eureka服务注册地址
  client:
    #是否从eureka Server 抓取已有的注册信息,默认true,单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
    fetch-registry: true
    #表示是否将自己加入eureka service true代表加入
    register-with-eureka: true
    service-url:
      #      #设置 eureka server 交互的地址查询服务和注册服务需要依赖的地址
      defaultZone: http://eureka7001.com:7001/eureka

主启动: 只需添加EnableEurekaClient注解即可

@SpringBootApplication
@EnableEurekaClient
public class Gateway9527 {
    public static void main(String[] args) {
        SpringApplication.run(Gateway9527.class,args);
    }
}

我们启动项目:访问 http://localhost:9527/get/1 可以直接转发到http://localhost:8001/get/1的接口在这里插入图片描述在这里插入图片描述
从而可以做到,隐藏真实的服务端口,而提供相应的服务,增加了服务的安全性。

这是诸多配置里面的一种,按照请求路劲进行(predicates)断言到相应的服务中去,除此之外,还有很多

此处不多演示了:

#            通过路径进行断言路由
            -  Path=/get/**
#            通过请求时间  如果请求时间不在对应时间之后则请求失败
#            - After=2020-09-19T06:06:06+08:00[Asia/Shanghai]
#            通过请求时间  如果请求时间不在对应时间之前则请求失败
#            - Before=2020-09-19T06:06:06+08:00[Asia/Shanghai]
#            通过cookie
#            - Cookie=cpown, cpown

下面有一张图可以简单地看一下所有的可配置元素:
在这里插入图片描述

五、实现java编码配置Route

上面讲了通过配置文件,配置相应的 Gateway predicates,还有另一种方式进行配置那就是代码配置:
先注释掉application.yml里面的配置:
在这里插入图片描述

可以在启动类里面添加Bean的注册,也可以创建自己的Config文件:

@SpringBootApplication
@EnableEurekaClient
public class Gateway9527 {
    public static void main(String[] args) {
        SpringApplication.run(Gateway9527.class,args);
    }

	//添加Bean实例
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/get/**")
                        .uri("lb://cloud-payment-service"))
                .build();
    }
}

在这里插入图片描述
效果也是一样的。

五、实现java编码配置Filter

Spring Cloud Gateway 除了上述的路由 Route 与 Preicate断言以外,还支持请求的过滤以及增强操作:Filter
有点类似于我们之前的说的 :过滤器interceptor

package com.cpown.springcloud.config;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MygateWayFilter implements GlobalFilter, Ordered {

    /**
     * 类似于 过滤器interceptor 可以对请求进行判断,增强,以及校验
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String name = request.getQueryParams().getFirst("name");
        //如果参数为 空 不予通过 直接报错
        if (StringUtils.isEmpty(name)) {
            response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return response.setComplete();
        }
        return chain.filter(exchange);
    }

    /**
     * 此方法仅设置排序顺序无需改动
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

我们 创建一个MygateWayFilter全局过滤组件组件,可以对所有的请求进行Filter处理,判断是否包含参数 “name”,如果不包含则不予通过,包含则通过:
再次请求:http://localhost:9527/get/1 发现已经无法通过。

在这里插入图片描述
修改请求为:http://localhost:9527/get/1?name=cc 又可以恢复调用。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值