柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • Java基础

  • JavaWeb

  • 拓展技术

  • 框架技术

  • 数据库

  • 数据结构

  • Spring

  • SpringMVC

  • SpringBoot

  • SpringClound

    • SpringCloud认知
    • SpringCloud Eureka注册中心
    • SpringCloud Ribbon负载均衡
    • SpringCloud Hystrix熔断器
    • SpringCloud Feign
    • SpringCloud Gateway网关
      • 核心功能
      • 工作流程
      • 过滤器
        • 自定义局部过滤器
        • 自定义全局过滤器
      • 跨域配置
      • 负载均衡&熔断器
      • Gateway与Feign的区别
    • SpringCloud Config配置中心
    • SpringCloud Bus服务总线
  • Ruoyi-Vue-Plus

  • 后端
  • SpringClound
柏竹
2021-10-31
目录

SpringCloud Gateway网关

# Gateway 网关

Spring Cloud Gateway 网关 组件核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对 应的服务。

补充说明&优点

  • Gateway 替换了 Netflix Zuul 的一套解决方案
  • 隐藏 服务的 IP/端口 等信息
  • 提供统一的API路由管理方式 (url管理)
  • Gateway 核心功能 过滤/路由/断言
  • Gateway 也是个微服务,需要注册到 Eureka

# 核心功能

  • Route (路由) :路由信息由 ID、目标URL、一组断言、一组Filter 组成 (一般情况会通过断言进行判断 路由匹配)
  • Predicate (断言) :定义匹配的 HTTP 中的任何信息(如:请求头/参数等...
  • Filter (过滤器) :可在 请求/响应 进行一些业务上的处理

# 工作流程

说明:

  • 客户端 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 的微服务中进行处理,此时处理运行特定的请求过滤器链

  • 过滤器虚线分开的原因:会在发送代理请求的 请求/响应 执行逻辑(所有 pre 过滤器逻辑先执行,然后执行 代理请求;代理请求完成后,执行 post 过滤器逻辑,进行响应)

示例

代码在 01Spring Cloud (opens new window) 的基础上进行编辑

  1. 创建新Maven工程(无骨架) 我创建的工程名称 gateway

  2. gateway 依赖配置 pom.xml

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

    @SpringBootApplication
    @EnableDiscoveryClient // Eureka客户端
    public class GatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(GatewayApplication.class, args);
        }
    }
    
  4. gateway 配置 application.yml

    server :
        port : 10010
    spring :
        application :
            name : api-gateway
        cloud :
            gateway :
                routes :
                    # 路由id (随意)
                    - id : user-service-route
                      # 代理服务的地址
    #                 uri: http://localhost:9091  # 方式1 固定代理
                      uri : lb://user-service  # 方式2 动态代理
                      # 路由断言,可以配置的映射路径
                      predicates:
                        - Path=/user/**
    eureka :
        client :
            service-url :
                defaultZone : http://localhost:10086/eureka
        instance :
            # 优先应用ip,并非 host
            prefer-ip-address : true
    

    注意:

    • 填写路由断言的路径 不能存在空格 - Path=/user/**

    说明:

    • 代理路径 http://localhost:10010/user/1 (opens new window) ==> http://localhost:9091/user/1 (opens new window)
    • 代理路由 有两种方式写,但一般不会写死,因此应用第二种方式
    • 路由配置中uri所用的协议为lb时,gateway 将使用 LoadBalancerClient 把 user-service 通过 eureka 解析为 实际IP 和 端口,并进行ribbon负载均衡
  5. 测试

    1. 依次打开 Eureka、server、gateway 三个服务
    2. 访问 http://localhost:10010/user/1 (opens new window)(返回 数据代表成功)

# 过滤器

通过以上工作流程可得知 ,Gateway 的路由 过滤器允许 修改传入 请求/响应 的HTTP,只作用于特定的路由

过滤器生命周期

Spring Cloud Gateway 的 Filter 有两种: pre(请求被执行前调用)、post(请求被执行后调用) ,以上的工作流程可看出

使用场景

  • 请求鉴权:过滤器链式 调用到 filter()方法 前,如果发现无权限,返回Null
  • 异常处理:过滤器链式 调用到 filter()方法 后,记录异常并返回
  • 服务调用时长统计:过滤器链式 调用到 filter()方法 前后,根据时长统计

常用过滤器工厂

Gateway 中有很多内置的过滤器工厂,我们只需了解常用的过滤器

过滤器工厂名称 说明
AddRequestHeader 对匹配上的请求加上Header(请求头)
RemoveRequestHeader 对匹配上的请求去除Header(请求头)
AddRequestParameter 对匹配上的请求路由添加参数
SetStatus 设置 HTTP请求 的响应码
AddResponseHeader 对从网关返回的响应添加Header(响应头)
StripPrefix 对匹配上的请求路径去除前缀
PrefixPath 对匹配上的请求路径添加前缀

更多详细参考 官网链接 (opens new window)

过滤器示例

AddRequestHeader 添加请求头

符合规则匹配成功的请求,将添加 X-Request-Foo:bar 请求头,将其传递到后端服务中

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                - id : user-service-route
                  uri : lb://user-service
                  predicates:
                      - Path=/user/**
                  filters:
                  	  # 参数:请求头,值
					  - AddRequestHeader=X-Request-Foo,Bar

RemoveRequestHeader 移除请求头

可以在请求转发到后端服务之前进行 Header 的移除操作

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                - id : user-service-route
                  uri : lb://user-service
                  predicates:
                      - Path=/user/**
                  filters:
                  	  # 参数:移除请求头 X-Request-Foo
					  - RemoveRequestHeader=X-Request-Foo

AddRequestParameter 请求添加参数

符合规则匹配成功的请求,将会附加 MyName=Sans 参数

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                - id : user-service-route
                  uri : lb://user-service
                  predicates:
                      - Path=/user/**
                  filters:
                  	  # 参数:名称,值 (类似于 K , V)
					  - AddRequestParameter=MyName,Sans

SetStatus 响应返回码

用于设置 HTTP请求 的响应码 ; 支持 整数/枚举 (org.springframework.http.HttpStatus类 查看枚举)

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                - id : user-service-route
                  uri : lb://user-service
                  predicates:
                      - Path=/user/**
                  filters:
					  - SetStatus=401

AddResponseHeader 添加响应头

网关响应添加响应头

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
        	default-filters:
        		- AddResponseHeader=X-Request-Foo,Bar

StripPrefix 去除路由前缀

对请求地址前缀去除后,再作为 代理地址

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                # 路由id (随意)
                - id : user-service-route
                  # 代理服务的地址
#                  uri: http://localhost:9091  # 方式1
                  uri : lb://user-service  # 方式2
                  # 路由断言,可以配置的映射路径
                  predicates:
                    - Path=/api/user/**
                  filters:
                    - StripPrefix=1
···

​ 如: http://localhost:10010/api/user/1 (opens new window) ==> http://localhost:9091/user/1 (opens new window) (去除/api)

PrefixPath 添加路由前缀

对请求地址添加前缀后,再作为 代理地址

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            routes :
                # 路由id (随意)
                - id : user-service-route
                  # 代理服务的地址
#                  uri: http://localhost:9091  # 方式1
                  uri : lb://user-service  # 方式2
                  # 路由断言,可以配置的映射路径
                  predicates:
                    - Path=/**
                  filters:
                    - PrefixPath=/user
···

​ 如: http://localhost:10010/1 (opens new window) ==> http://localhost:9091/user/1 (opens new window) (添加/user)

测试可自行在以下的自定义过滤器工厂测试检查属性变化

# 自定义局部过滤器

Spring Cloud Gateway 过滤器工厂 ,在请求传递的过程中,对请求进行 编辑/验证。(应用场景一般有:身份验证、选择集群中指定的微服务 等...

示例

说明:

  • 自定义过滤器工厂需要继承 AbstractGatewayFilterFactory类,重写 apply()方法 , 且过滤器类命名以 GatewayFilterFactory 为后缀
  • 测试 请求参数 在控制台展示
  1. 创建 自定义局部过滤器 (我创建的MyParamGatewayFilterFactory

    package com.sans.gateway.filter;
    
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.List;
    
    @Component
    public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {
        
        /**构造函数*/
        public MyParamGatewayFilterFactory() {
            super(Config.class);
        }
        /** 初始化
         * 读取配置文件中的参数,赋值到配置类中
         * */
        @Override
        public List<String> shortcutFieldOrder() {
            //一个参数
            return Arrays.asList("params");
        }
        
        /**过滤器逻辑*/
        @Override
        public GatewayFilter apply(Config config) {
            // 实例化 GatewayFilter.filter()
            //      exchange - 请求属性
            //      chain - 提供一种委托给下一个过滤器的方法
            return (exchange , chain) -> {
                // 前置
                ServerHttpRequest request = exchange.getRequest();
                // 路由包含 name参数 则执行
                if (request.getQueryParams().containsKey(config.params)) {
                    request.getQueryParams().get(config.params).forEach((v)->{
                        System.out.printf("局部过滤器 => %s = %s\n",config.params,v);
                    });
                }
        
        /**读取过滤器配置的参数 (以对象形式存储*/
        public static class Config {
            // 对应配置在 application.yml 配置文件中的过滤参数
            private String params;
        
            public String getParams() {
                return params;
            }
        
            public void setParams(String params) {
                this.params = params;
            }
        }
        
        
    }
    
  2. 配置 application.yml 添加 自定义过滤器

    spring :
        cloud :
            gateway :
                routes :
                    # 路由id (随意)
                    - id : user-service-route
                      # 代理服务的地址
    #                  uri: http://localhost:9091  # 方式1
                      uri : lb://user-service  # 方式2
                      # 路由断言,可以配置的映射路径
                      predicates:
                          - Path=/user/**
                      filters:
                          # 添加自定义过滤器
                          - MyParam=name
    

    说明:

    • 在配置中 过滤器指定可省略 GatewayFilterFactory 后缀
    • 以上对应参数是 shortcutFieldOrder()方法 返回指定参数数量的List (以上我指定返回一个参数params 的List)
  3. 测试

    1. 依次打开 Eureka、server、gateway 三个服务
    2. 访问 http://localhost:10010/user/1?name=Sans (opens new window)

    访问后,控制台会打印,若参数名name不匹配,则不打印

# 自定义全局过滤器

全局过滤器作用于所有路由, 无需其他配置!!!一般情况用于权限统一验证,安全验证等功能...

示例

说明:

  • 全局过滤器 需要实现 GlobalFilter接口
  • 过滤器顺序 需要实现 Ordered接口 指定数值(值越小越快
  • 测试 请求是否授权 。判断是否包含 token 的请求头
  1. 创建 自定义全局过滤器 (我创建的MyGlobalFilter

    package com.sans.gateway.filter;
    
    import org.apache.commons.lang.StringUtils;
    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.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    public class MyGlobalFilter implements GlobalFilter, Ordered {
        
        @Override
        public Mono<Void> filter(ServerWebExchange exchange , GatewayFilterChain chain) {
            System.out.println("=================全局过滤器MyGlobalFilter=================");
            
            String token = exchange.getRequest().getHeaders().getFirst("token");
            if (StringUtils.isBlank(token)) {
                // 设置响应状态码为未授权 401
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            
            return chain.filter(exchange);
        }
        
        /**设置过滤器优先顺序*/
        @Override
        public int getOrder() {
            return 1;
        }
    }
    
  2. 测试 (由于需要为请求添加请求头)

    1. 依次打开 Eureka、server、gateway 三个服务
    2. 通过 以下的IDEA内置的HTTP测试 以下有示例

    说明: 请求成功会 返回数据 ;请求失败会返回401 (未授权)

IDEA内置HTTP调试

  1. 创建测试 HTTP请求 草稿文件

  2. 设置请求url测试

    有示例查看使用方式等功能...

# 跨域配置

跨域:当一个请求URL的 协议/域名/端口 之间任意一个与当前页面URL不同,称为跨域

当前 URL 被请求URL 是否跨域 原因 比较
http://www.test.com/ http://www.test.com/index.html N - -
http://www.test.com/ https://www.test.com/index.html Y 协议不同 http/https
http://www.test.com/ http://www.baidu.com/ Y 主域名不同 test/baidu
http://www.test.com/ http://blog.test.com/ Y 子域名不同 www/blog
http://www.test.com:8080/ http://www.test.com:7001/ Y 端口号不同 8080/7001

这一跨域问题可通过 Gateway 网关服务器中配置即可。配置如下:

spring :
    application :
        name : api-gateway
    cloud :
        gateway :
            globalcors :
                cors-configurations :
                    # 代表所有访问到网关服务器上的地址
                    '[/**]' :
                    	# 允许指定服务器地址访问 
#                        allowedOrigins : *     # *代表全部支持访问
                        allowedOrigins :
                            - "http://demo.sans.top"
                        allowedMethods :
                            - GET

上述配置 允许来自 http://demo.sans.top 的 GET请求 获取服务数据

官方具体了解:CORS Configuration (spring.io) (opens new window)

# 负载均衡&熔断器

Gateway 默认集成 Ribbon、Hystrix (配置策略也如此)。如有其它策略配置可点击一下链接了解相关配置

  • Spring Cloud Feign (opens new window)
  • Spring Cloud Hystrix_熔断器 (opens new window)
  • Spring Cloud Ribbon_负载均衡 (opens new window)

# Gateway与Feign的区别

Gateway Feign
接口入口 统一服务入口 单一微服务入口
接口安全 接口隐蔽应用 接口暴露应用
路由处理 可以处理 固有。不能处理
应用场景 权限检查、控制流量 微服务内部调用更方便

仓库代码 : https://gitee.com/Bozhu12/spring-cloud-examples.git (opens new window)

#SpringClound#Java

← SpringCloud Feign SpringCloud Config配置中心→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式