返回顶部
首页 > 资讯 > 后端开发 > Python >基于SpringCloudGateway实现微服务网关的方式
  • 102
分享到

基于SpringCloudGateway实现微服务网关的方式

2024-04-02 19:04:59 102人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录(一)什么是微服务网关(二)spring cloud Gateway网关2.1 核心概念:2.2 搭建环境:(三) 路由配置详解3.1 自定义断言配置3.2 断言不匹配404页面

(一)什么是微服务网关

后端写完所有的微服务之后,最终是要交给前端去调用。我们都知道每个微服务都有各自的端口号,如果前端直接通过IP加端口的方式去调用微服务会很麻烦。如果想对请求增加限制也会变得十分困难。这个时候微服务网关就出现了。

微服务网关又成为api网关,它是系统对外的唯一入口。APl网关封装了系统内部架构,为每个客户端提供一个定制的APl。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/Http的访问API。服务端通过API-GW注册和管理服务。

听起来有些抽象,下面就做一张图给大家展示一下:前端的请求统一由微服务网关进行管理,微服务网关可以调用各个微服务,同时自身还有多种功能。

API网关的职责有身份验证、监控负载均衡缓存、请求分片与管理、静态响应处理,最重要的功能是和外界联系。

常见的API网关实现方式有Zuul,traefix,Spring Cloud Gateway等等。目前主流的微服务网关是Spring Cloud Gateway。

(二)Spring Cloud Gateway网关

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

2.1 核心概念:

路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL,一组断言工厂和一组Filter组成。

断言(predicates):java8中的断言函数,Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自Http Request中的任何信息。当断言为真时,则匹配路由。

过滤器(filter):对请求和响应进行过滤

下面通过实践来操作微服务网关,本项目有依赖于Nacos与Sentinel,如果不需要这部分的内容可以在配置文件中去除。

2.2 搭建环境:

1、引入工程导入依赖

创建api_gateway_server工程,在工程中的pom.xml中导入依赖,项目全局依赖如下:


<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javayz</groupId>
    <artifactId>nacos-discovery-spring-cloud-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-discovery-spring-cloud-gateway</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <projec.build.sourceEncoding>UTF-8</projec.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
 
        <!--SpringCloudgateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
            <version>1.7.2</version>
        </dependency>
    </dependencies>
 
    <!--当前项目继承的依赖-->
    <dependencyManagement>
        <dependencies>
            <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>
 
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
 
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
 
        </dependencies>
    </dependencyManagement>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

2、配置启动类

创建GatewayApplication类


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

3、编写配置文件

这里对配置文件的编写使用.yml格式的配置文件,在resource文件夹下创建applicaiion.yml。这里需要注意的是gateway下routes的配置,首先用id自定义网关;接着定义uri,意思是当访问的是9090端口(即访问的是网关时),就自动把ip和端口号变成该uri;最后写断言predicates,这里的Path=/index @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route(RequestPredicates.all(),this::renderErrorResponse); } @Override protected int getHttpStatus(Map<String, Object> errorAttributes) { return (int) errorAttributes.get("status"); } private String buildMessage(ServerRequest request,Throwable ex){ StringBuilder builder = new StringBuilder("Failed to handle request:"); builder.append(request.methodName()); builder.append(" "); builder.append(request.uri()); if (ex!=null){ builder.append(ex.getMessage()); } return builder.toString(); } public static Map<String,Object> response(int status,String errORMsg,Object data){ Map<String,Object> map=new HashMap<>(); map.put("code",status); map.put("message",errorMsg); map.put("data",data); return map; } }

新建一个类叫做MyErrorWEBExceptionHandler:

再编写一个配置类,将自定义的异常页面代码注入到Bean容器中:


@Configuration
public class GatewayConfiguration {
    private final ServerProperties serverProperties;
    private final ApplicationContext applicationContext;
    private final ResourceProperties resourceProperties;
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
 
    public GatewayConfiguration(ServerProperties serverProperties, ApplicationContext applicationContext, ResourceProperties resourceProperties, ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
        this.serverProperties = serverProperties;
        this.applicationContext = applicationContext;
        this.resourceProperties = resourceProperties;
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
 
    @Bean("myErrorWebExceptionHandler")
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ErrorWebExceptionHandler myErrorWebExceptionHandler(ErrorAttributes errorAttributes){
        MyErrorWebExceptionHandler exceptionHandler=new MyErrorWebExceptionHandler(
                errorAttributes,
                this.resourceProperties,
                this.serverProperties.getError(),
                this.applicationContext
        );
        exceptionHandler.setViewResolvers(this.viewResolvers);
        exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
        exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
        return exceptionHandler;
    }
}

最后访问到404就会以JSON的格式返回,方便调用方做处理。

(四)Spring Cloud Gateway过滤器

Spring Cloud Gateway除了具有请求路由功能之外,也支持对请求的过滤。

生命周期:

过滤器有两种生命周期,PRE和POST:

PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。

POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

过滤器类型:

GatewayFilter:应用到单个路由或者一个分组的路由上

GlobalFilter:应用到所有的路由上

局部过滤器可以使用Spring Cloud Gateway内置的方法,在官网中(docs.spring.io/spring-clou…

官方过滤器:

这里简单介绍几个:


spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

添加AddRequestHeader过滤器后,每次请求转发给微服务后都会在header种增加一个X-Request-red。

- AddRequestParameter=red, blue

添加Request参数,每次请求转发给微服务后都会增加一个请求参数。

自定义全局过滤器: 创建一个Filter包,在包下新建GatewayFilter类,自定义全局过滤器需要继承GlobalFilter, Ordered接口,并重写接口的两个方法


@Component
public class GatewayFilter implements GlobalFilter, Ordered {
    //在里面写过滤器的逻辑
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入了过滤器");
        //表示继续向下执行
        return chain.filter(exchange);
    }
    //过滤器的优先级,数值越小,优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}

通过访问可以看到控制台上出现了打印的信息。

模拟用户认证过程:

全局过滤器可以实现对全局的用户验证。修改gatewayFilter,编写失败的逻辑,如果获取到的request请求中第一个属性不是access-token或为空,则返回HttpStatus.UNAUTHORIZED的报错


@Component
public class GatewayFilter implements GlobalFilter, Ordered {
    //在里面写过滤器的逻辑
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("进入了过滤器");
        String token = exchange.getRequest().getQueryParams().getFirst("access-token");
        if (token==null){
            //如果不存在,认证失败
            System.out.println("没有登陆");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    //过滤器的优先级,数值越小,优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}

在浏览器中输入:http://localhost:9090/sentinel/test1,出现报错,因为没有access-token

在浏览器中输入:http://localhost:9090/sentinel/test1?access-token=1,获取正确结果。

(五) 网关限流

在实际环境中会遇到这样的问题,同一时间会有许多请求去调用微服务,大量请求的进入很有可能导致微服务被破环,因此限流就变得很重要。

5.1 常见的一些限流算法:

计数器算法:设定一个单位时间内的计数值,如果单位时间内访问的请求大于这个设定的值,则之后的请求都拒绝。直到单位时间内的值低于这个值才继续接收。

漏桶算法:我们可以把漏桶算法想象成一个漏斗。请求进来时先到漏斗中,然后按设定好的输出速率分配到微服务上。当一下子有很多请求进来时,只能在漏斗上等着。为了控制流量,需要设置两个变量:一个是桶的大小,另一个是漏斗流出的速率。

令牌桶算法:令牌桶算法是对漏桶算法的一种改进,相比于漏桶算法,令牌桶算法能允许一定程度的突发调用。令牌桶算法的原理:在令牌桶算法中,存在一个桶,用来存放固定数量的令牌,令牌会以一定速率放到桶中,桶中的令牌满了之后就不会再放令牌。当一个请求来临时,要先在令牌桶中拿到一个令牌,才能去调用微服务,当令牌桶中没有令牌的时候,后来到的请求就需要等待。令牌桶算法除了可以限流,还允许一定程度的突发调用:比如一个令牌桶的容量是100,在没有请求的时候,令牌桶中的令牌数量是满的。此时如果突然来了100个请求,那么这100个请求都能被立刻执行。

5.2 集成Sentinel进行限流

添加依赖


<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    <version>1.7.2</version>
</dependency>

添加Sentinel配置:


spring:
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: localhost:8080

将Sentinel过滤器注入到Bean容器中


@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter(){
    return new SentinelGatewayFilter();
}

这样就可以用Sentinel的方式对网关进行限流了。

对于限流后的错误提示,我们可以修改默认错误提示方式,改成自定义或者跳转到错误页面:


@Configuration
public class GatewayConfiguration {
    private final ServerProperties serverProperties;
    private final ApplicationContext applicationContext;
    private final ResourceProperties resourceProperties;
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
 
    public GatewayConfiguration(ServerProperties serverProperties, ApplicationContext applicationContext, ResourceProperties resourceProperties, ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
        this.serverProperties = serverProperties;
        this.applicationContext = applicationContext;
        this.resourceProperties = resourceProperties;
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
 
    //自定义一个错误处理
    @Bean(name = "myBlockRequestHandler")
    public BlockRequestHandler myBlockRequestHandler(){
        BlockRequestHandler blockRequestHandler=new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                return ServerResponse.status(HttpStatus.BAD_GATEWAY)
                        .contentType(MediaType.APPLICATION_jsON)
                        .body(BodyInserters.fromValue("服务被限流了"));
            }
        };
        return blockRequestHandler;
    }
 
    //用自定义的handler替换掉默认的,或者重定向
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(BlockRequestHandler myBlockRequestHandler){
        //自定义Block处理
        GatewayCallbackManager.setBlockHandler(myBlockRequestHandler);
 
        //重定向block处理
        //GatewayCallbackManager.setBlockHandler(new RedirectBlockRequestHandler("http://www.baidu.com"));
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }
 
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();
    }
}

5.3 网关实现跨域

这个和SpringBoot中解决跨域的思路类似,配置CorsConfig


@Configuration
public class CorsConfig {
 
    @Bean
    public CorsWebFilter corsWebFilter(){
        CorsConfiguration configuration=new CorsConfiguration();
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedOrigin("*");
 
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.reGISterCorsConfiguration("/*",configuration);
        return new CorsWebFilter(source);
    }
}

(六)总结

本章内容比较多,但是把SpringCloudGateway基本会遇到的内容都讲解了一遍,希望对你有帮助。

到此这篇关于基于SpringCloudGateway实现微服务网关的文章就介绍到这了,更多相关SpringCloudGateway 微服务网关内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 基于SpringCloudGateway实现微服务网关的方式

本文链接: https://lsjlt.com/news/160626.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 基于SpringCloudGateway实现微服务网关的方式
    目录(一)什么是微服务网关(二)Spring Cloud Gateway网关2.1 核心概念:2.2 搭建环境:(三) 路由配置详解3.1 自定义断言配置3.2 断言不匹配404页面...
    99+
    2024-04-02
  • Go微服务网关的实现
    目录Go微服务网关网络基础大纲OSI七层网络协议三次握手 与 四次挥手为啥会出现大量的close_waitTCP 为啥需要拥塞控制TCP 拥塞控制为啥会出现粘包,拆包,如何处理产生t...
    99+
    2024-04-02
  • springcloudgateway网关服务启动报错的解决
    目录gateway网关服务启动报错集成gateway报错原因分析gateway网关运行时报错问题(版本问题)父级中的版本问题原因:父项目中的jdk版本问题解决方法gateway网关服...
    99+
    2024-04-02
  • 基于JWT规范实现的认证微服务
    本文由公众号EAWorld翻译发表,转载需注明出处。作者:Marcelo Fonseca译者:白小白 原题:Building an authentication micro-service with JWT standard原文:...
    99+
    2023-06-05
  • 关于Promise基本方法的简单实现
    目录前言catch() 方法done() 方法finally() 方法Promise.all() 方法Promise.race() 方法Promise.resolve() 和 Pro...
    99+
    2024-04-02
  • 关于分布式锁的三种实现方式
    目录分布式锁实现方案基于数据库实现分布式锁基于Zookeeper实现分布式锁加锁和解锁流程利用curator实现基于缓存实现分布式锁,以Redis为例三种方案比较Java中的锁主要包括synchronized锁和JUC包...
    99+
    2024-04-02
  • SpringCloud微服务开发基于RocketMQ实现分布式事务管理详解
    目录消息队列实现分布式事务原理RocketMQ的事务消息代码实现基础配置发送半消息执行本地事务与回查Account-Service消费消息测试小结消息队列实现分布式事务原理 首先让我...
    99+
    2024-04-02
  • 关于Object.entries()方法的使用和实现方式
    Object.entries()方法的使用和实现 1、定义 Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该...
    99+
    2023-02-10
    Object.entries()方法 使用Object.entries() Object.entries()
  • 基于Sanic的微服务基础架构
    使用python做web开发面临的一个最大的问题就是性能,在解决C10K问题上显的有点吃力。有些异步框架Tornado、Twisted、Gevent 等就是为了解决性能问题。这些框架在性能上有些提升,但是也出现了各种古怪的问题难以解决。...
    99+
    2023-01-31
    架构 基础 Sanic
  • 基于 Redis 实现接口限流的方式
    目录基于 Redis 实现接口限流1. 准备工作2. 限流注解3. 定制 RedisTemplate4. 开发 Lua 脚本5. 注解解析6. 接口测试7. 全局异常处理总结基于 R...
    99+
    2024-04-02
  • 基于Redis实现阻塞队列的方式
    日常需求开发过程中,不免会遇到需要通过代码进行异步处理的情况,比如批量发送邮件,批量发送短信,数据导入,为了减少用户的等待,不希望一直菊花转啊转,因此需要进行异步处理,做法就是讲要处...
    99+
    2024-04-02
  • 基于Go语言的微服务架构设计与实现
    随着云计算和容器化技术的快速发展,微服务架构已经成为了构建大型分布式系统的首选架构之一。微服务架构的核心理念是将复杂的单体应用拆分成一系列小而独立的服务,通过轻量级的通信方式进行交互,从而提高系统的可伸缩性、可靠性和可维护性。而Go语言作为...
    99+
    2023-11-20
    微服务 实现 架构设计
  • 关于工厂方法模式的Java实现
    目录工厂方法模式简述创建步骤步骤1步骤2步骤3步骤4步骤5工厂方法模式简述 与简单工厂模式基本相同,只是工厂是一个抽象的,需要有具体的工厂去实现它,然后利用这个工厂生产产品,之所以出...
    99+
    2024-04-02
  • 基于C#实现Windows服务的方法详解
    目录前言Windows服务介绍创建Windows服务安装卸载Windows服务前言 在实际应用过程中,有时候我们希望开发的程序,不需要界面,直接开机就可以长时间运行,这时候,我们可以...
    99+
    2024-04-02
  • 基于Java方式实现数据同步
    本文实例为大家分享了Java方式实现数据同步的具体代码,供大家参考,具体内容如下 使用java方式实现两个系统之间数据的同步。 业务背景 在新系统中设置定时任务需要实时把客户系统中的...
    99+
    2022-11-13
    java 数据同步
  • 百亿流量微服务网关的设计与实现
    本文从百亿流量交易系统微服务网关(API Gateway)的现状和面临的问题出发,阐述微服务架构与 API 网关的关系,理顺流量网关与业务网关的脉络,分享API网关知识与经验。API网关概述“计算机科学领域的任何问题都可以通过增加一个间接的...
    99+
    2023-06-05
  • springsecurity如何实现基于token的认证方式
    这篇文章主要为大家展示了“springsecurity如何实现基于token的认证方式”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“springsecurity如何实现基于token的认证方式”...
    99+
    2023-06-20
  • 关于python线程池的四种实现方式
    目录python 线程池的四种实现方式线程简述方式1 multiprocessing.dummy Pool()方式2:multiprocessing.pool ThreadPool ...
    99+
    2023-05-16
    python线程池 python线程池实现
  • 关于QueryWrapper,实现MybatisPlus多表关联查询方式
    目录QueryWrapper实现MybatisPlus多表关联查询1.dao层接口使用Select注解写SQL2.service层代码示例3.反射工具类4.判空工具类Myb...
    99+
    2024-04-02
  • Go 语言下基于Redis分布式锁的实现方式
    分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作