一文带你吃透微服务守门神SpringCloud-GateWay

GateWay简单介绍

一句话:网关是微服务架构系统的守门神 网关本身是一个微服务,是所有微服务的入口。鉴权、限流、路由、监控【监控所有方法执行调用时间】
在这里插入图片描述

Gateway和Zuul的对比:

1.gateway是zuul的代替者。并不是zuul有什么大问题 而是后面zuul宣布闭源了 所以springcloud自己做了一个gateway后来就不再集成zuul了

2.Zuul是基于servlet阻塞式的并且不支持任何长连接 gateway是使用Reactor和springboot开发的 使用非阻塞式的API 性能要优于zuul

gateWay的几个核心概念

非常重要!

必须要对这几个概念熟悉了 才能分析他的高级特性以及功能

1. route/路由:路由是网关的最基本组成,由一个路由 id、一个目标地址 url,一组断言工厂及一组
filter组成。若断言为 true,则请求将经由 filter 被路由到目标 url。 一句话理解 就是定义一条游戏规则

2. predicate断言:断言即一个条件判断,根据当前的 http 请求进行指定规则的匹配,比如说 http
请求头,请求时间等。只有当匹配上规则时,断言才为 true,此时请求才会被直接路由到目标地址
(目标服务器),或先路由到某过滤器链,经过过程器链的层层处理后,再路由到相应的目标地址
(目标服务器)。一句话理解 就是定义一个游戏规则中的多个小规则

3. filter过滤器:对请求进行处理的逻辑部分。当请求的断言为 true 时,会被路由到设置好的过滤
器,以对请求进行处理。例如,可以为请求添加一个请求头,或添加一个请求参数,或对请求URI
进行修改等。总之,就是对请求进行处理。 一句话理解 对请求做过滤

入门案例

需求:访问网关服务跳转到百度(静态路由)

1.创建工程并且加入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud-alibaba-sxw-parent</artifactId>
        <groupId>com.sxw</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>03-gateway-simple</artifactId>

    <properties>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- actuator依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <!-- spring-cloud的依赖-->
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- spring-cloud-alibaba的依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

2.配置文件

server:
  port: 9000

spring:
  cloud:
    gateway:
      #添加一组路由
      routes:
          #路由id 唯一标识/名字
        - id: route_to_baidu
          #路由到的目标地址
          uri: http://www.baidu.com
          #断言 也就是规则 我需要定义什么样的请求被被这个路由拦截
          predicates:
            - Path=/**

3.测试
在这里插入图片描述
4.这是使用配置文件配置 也可以使用java类代码来配置

//区别在于可以直接声明好 不需要在配置文件上修改
@SpringBootApplication
public class ApiConfigGateWayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiConfigGateWayApplication.class, args);
    }

    @Bean
    //使用的是构建者模式+java8 lambda的语法来编写 优雅简单
    public RouteLocator locator(RouteLocatorBuilder builder){
        return builder.routes().route(predicateSpec -> predicateSpec
                .path("/**")
                .uri("https://www.baidu.com")
                .id("api_config_route_to_baidu"))
                .build();
    }
}

网关层负载均衡

需求:我的服务组成了集群 那么网关支持负载均衡吗? 当然支持
在这里插入图片描述
1.pom依赖

小疑问 为什么需要加入注册中心的依赖?
因为网关本身也是一个微服务 那么也可以将他注册到配置中心
负载均衡 顾名思义 用过feign的同学就知道 有点像域名找服务一样

<!-- 注册中心支持 其他依赖省略... 这里使用nacos作注册中心 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2.配置文件(同样可以使用java配置类的方式进行配置)

这里主要关注这个路由规则
uri这个参数:lb://provider
lb:是网关自有的协议 至于为什么叫lb 因为源码已经写死 感兴趣的可以自己查阅ribbon中的实现
provoder:这个其实就是服务名字 这个服务的集群不管有几个 服务名是不变的
这样就可以通过nacos找到这个名字背后的集群地址 通过某种负载均衡机制找到具体某一台 然后进行请求转发

erver:
  port: 9002

spring:
  application:
    name: sxw-gateway-ribbon
  #注册中心配置
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  #开启与discoveryClient的整合
    gateway:
      discovery:
        locator:
          enable: true
      #路由配置
      routes:
        - id: ribbon_route
          uri: lb://provider
          predicates:
            - Path=/provider/depart/**

3.修改均衡策略 随机负载均衡策略

@Bean
public IRule loadBalanceRule(){
    return new RandomRule();
}

4.启动提供者服务provider集群
在这里插入图片描述

5.验证
···
http://localhost:9002/provider/depart/get/122
···

gateWay 工作原理

在这里插入图片描述

三大组件:高级工作原理图(左) 粗

网关处理器映射器组件 HandlerMapping
网关WEB处理器组件Web Hnadler
网关过滤器组件Filter**

工作流程:

组装网关上下文->循环遍历所有的Mapper获取Handler->匹配路由信息,如果断言失败就返回->进入Filter过滤链条调用链->前置过滤器->自定义过滤器->后置过滤器

网关路由断言工厂(路由规则)

path路由规则:

含义:对这个路径进行拦截
如 - Path=/info/** 请求地址:http://localhost:9000/info/hello 那么就会被path_showinfo_route这个路由拦截转发到http://localhost:8088这个服务
也可以理解 访问 http://localhost:9000/info/hello 等同于访问 http://localhost:8088/info/hello

1.添加两组路由策略

server:
  port: 9000

spring:
  cloud:
    gateway:
      #配置断言工厂1 路由到http://localhost:8999 这个服务
      routes:
        - id: path_consumer_route
          uri: http://localhost:8999
          predicates:
            - Path=/consumer/depart/**
        #配置断言工厂2 路由到http://localhost:8088 这个服务
        - id: path_showinfo_route
          uri: http://localhost:8088
          predicates:
            - Path=/info/**

2.测试

测试1:http://localhost:9000/consumer/depart/get/1
测试2:http://localhost:9000/info/hello

After路由规则:

一句话 配置的时间要比现在的时间小才能够访问 格式固定
如下:这样是不能访问的

配置文件

server:
  port: 9000

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: http://www.baidu.com
          predicates:
            - After=2022-01-20T17:42:47.789-07:00[Asia/Shanghai]

其他路由规则

举一反三:基本的玩法就是配置 根据你的业务需要进行配置即可 不需要全部背熟 常用的还有如下这几种

  • Before
  • Between
  • Cookie
  • Header
  • Host
  • Method

网关过滤器

分类

  • 局部过滤器:应用于单个路由策略上,其功能仅对路由断言为 true 的请求起作用
  • 全局过滤器:应用于所有路由策略上,其功能就像前面的配置文件中设置的默认 Filter

PrefixPath 过滤器(局部)

任何请求都会进行拦截 并在请求地址上增加/info然后将请求转发到目标地址
localhot:9999/findById?id=1 添加之后: localhost:8088/info/findById?id=1
有啥用?保护我们的接口地址 防止被人恶意攻击

spring:
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          uri: http://localhost:8088
          predicates:
            - Path=/**
          filters:
            - PrefixPath=/info

去除前缀过滤器(局部)

举一反三
localhost:9999/user/findById?id=1 去除之后 localhot:9999/findById?id=1

自定义过滤器(重要)

当内置的过滤器不满足业务需要时 当然也支持自定义的过滤器
比如支付有支付的独立网关,我们可以要求,所有的服务进入支付的相关服务之前需要有支付系统颁发的权限token,此时就可以在支付网关做这样一个校验支付token权限的事情。
需求:往请求头添加一个参数

1.编写自定义filter

public class  CustomerFilter implements GatewayFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.构建改变后的request对象
        ServerHttpRequest request = exchange.getRequest().mutate().header("X-Request-customer", "customer").build();
        //2.将改变的request对象置入exchange对象中
        ServerWebExchange webExchange = exchange.mutate().request(request).build();
        //3.设置修改后的exchange对象
        return chain.filter(webExchange);
    }
}

2.配置自定义过滤器生效

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
    return builder.routes().route(predicateSpec -> predicateSpec
            .path("/**")
            .filters(gfs-> gfs.filter(new CustomerFilter()))
            .uri("http://localhost:8088")
            .id("updateRequest"))
            .build();
}

3.另外一个服务(转发过去的服务)http://localhost:8088

@RestController()
@RequestMapping("/info")
public class InfoController {

    @GetMapping("/hello")
    public String hello(HttpServletRequest request){
        String header = request.getHeader("X-Request-customer");
        return "new header:" + header;
    }
}

4.测试
在这里插入图片描述

自定义全局过滤器

模拟鉴权 重要!
全局过滤器 针对所有的路由都生效 只需要交由spring容器管理即可
需求:判断当前请求是否携带了token 如果没有就返回错误信息 (实际开发应校验该token是否合法 也就是这个token存不存在 是否过期以及包含的用户是否合法)

1.定义全局过滤器

@Component
public class GlobalFilter implements org.springframework.cloud.gateway.filter.GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求中的token
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        //校验是否存在
        if (StringUtils.isEmpty(token)){
            //如果不存在 返回对应的错误码
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        //如果存在则放行请求
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //最高级别 返回的int值越大 优先级越高 spring-core的组件
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

2.定义一个路由规则 因为是全局的 不需要指定参数filter

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
    return builder.routes().route(predicateSpec -> predicateSpec
            .path("/**")
            .uri("http://localhost:8088")
            .id("global_filter_route"))
            .build();
}

3.测试
测试1不带 token访问:http://localhost:9004/info/hello
在这里插入图片描述
测试2:带token访问http://localhost:9004/info/hello?token=222
在这里插入图片描述

过滤器优先级

值越大优先级越高的原则
在这里插入图片描述

网关降级

当我们路由到的服务不可用时 一样会报错 此时我们期望 网关可以实现降级 为什么需要降级? 给用户友好提示 不要一堆报错信息 看不懂!

1.添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

2.定义降级处理器controller

@RestController
public class FallbackController {

    @RequestMapping("fallback")
    public Map<String,String> fallback(){
        Map<String,String> map = new HashMap<>();
        map.put("code","200");
        map.put("msg","服务降级");
        map.put("data",null);
        return map;
    }
}

3.编写降级配置(filter)-针对一个路由

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
    return builder.routes().route(predicateSpec -> predicateSpec
            .path("/**")
            .filters(fs->fs.circuitBreaker(config -> {
                //配置降级
                config.setName("myCircuitBreaker");
                config.setFallbackUri("forward:/fallback");
            }))
            .uri("http://localhost:8088")
            .id("global_filter_route"))
            .build();
}

4.测试针对一个路由降级 把提供者服务下线http://localhost:9004/info/hello?token=222
在这里插入图片描述
5.配置全局路由熔断 配置文件

spring:
  cloud:
    gateway:
      default-filters:
        - name: CircuitBreaker
         args:
           name: myCircuitBreaker
           fallbackUri: forward:/fallback 
      routes: 
        - id: test_filter 
          uri: http://localhost:8088 
          predicates: 
            - Path=/**

网关限流

针对一些恶意攻击 为了保护网关后面的服务 就可以将一些无效的请求拦截掉 这样的做法也是非常必要的

使用redis 令牌桶

令牌桶:

关键:1.桶(放redis 放令牌 放一定数量的令牌) 2.速率

含义:如果需要执行请求 需要去桶里拿到令牌 才能放行 否则被拒绝并返回

在这里插入图片描述

网关令牌桶限流(使用redis实现)

1.依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2.配置文件

spring:
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: requestRateLimiter_filter
          uri: http://localhost:8088
          predicates:
            - Path=/info/**
          filters:
            - name: RequestRateLimiter
              args:
                #  key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#
                key-resolver: "#{@keyResolver}"
                #  replenishRate:令牌桶每秒填充平均速率。
                redis-rate-limiter.replenishRate: 2
                #  burstCapacity:令牌桶总容量。
                redis-rate-limiter.burstCapacity: 5

3.配置类

Bean
//配置令牌同算法key:将主机名作为限流key
public KeyResolver keyResolver(){
    return exchange -> Mono.just(exchange
            .getRequest()
            .getRemoteAddress()
            .getHostName());
}

4.测试
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
操作系统是计算机系统中的核心组成部分,负责管理和协调计算机硬件和软件资源,提供程序运行环境。在CSDN上有很多关于操作系统的专题文章,以下将从操作系统的基本概念、功能和常见类型等方面简要介绍一下。 首先是操作系统的基本概念。操作系统是一种系统软件,它是计算机硬件和应用软件之间的桥梁,提供给应用程序一系列的服务和资源,同时负责调度和管理系统资源。它为用户屏蔽了底层的硬件差异,提供了一个统一的、易于使用的界面。 操作系统主要有四个基本功能。首先是处理器管理,负责将处理器分配给系统中的各个进程,并进行进程切换,实现多道程序并发执行。其次是内存管理,管理计算机的内存资源,包括分配、回收和保护等操作。再次是文件管理,负责管理文件的存储、命名和保护等操作,提供了文件操作的接口。最后是设备管理,负责管理计算机的各种设备,包括输入输出设备和存储设备等。 常见的操作系统有多种类型。最主流的是Windows、Linux和Mac OS等桌面操作系统。此外还有服务器操作系统,如Windows Server和Linux等,用于管理和部署服务器。还有嵌入式操作系统,如Android和iOS等,用于移动设备和物联网设备。操作系统也有实时操作系统,用于需要实时控制和响应的系统,如工控系统和航空航天系统等。 总之,操作系统是计算机系统中不可或缺的重要组成部分,通过CSDN上的相关文章,我们可以更深入了解操作系统的基本概念、功能和不同类型。这些知识对于理解计算机系统的工作原理和提升编程能力都有着重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值