百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

微服务改造之整合gateway(微服务 gateway)

liuian 2025-03-19 14:13 9 浏览

1.概述

Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。

为啥改造使用网关

前提条件:

  • Consul:版本1.5.0。
  • Spring boot:版本2.1.5。
  • Spring cloud:版本Greenwich.SR1。
  • Redis:版本5.0.5。

三大核心概念

  • 1、Route(路由) 路由是由构建万股干的基本模块,他由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
  • 2、Predicate(断言) 参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头和请求参数),如果请求与断言相匹配则进行路由
  • 3、Filter(过滤) 指的是Spring框架中的GatewayFilter的实例,使用过滤器,可以在请求被路由钱或者而之后对请求进行修改

gateway负载特点

  • 服务实例均衡分配:微服务负载均衡确保来自客户端的请求均匀分布到不同的服务实例上,以防止某些实例过载而其他实例处于空闲状态。
  • 多种负载均衡策略:微服务负载均衡可以采用不同的策略,如轮询、随机、最少连接等,以选择目标服务实例。每种策略有其用途,根据具体情况选择合适的策略。
  • 健康检查:负载均衡器定期检查每个服务实例的健康状态,以确定哪些实例可以接收请求。如果某个实例不健康或不可用,负载均衡器将停止将请求路由到该实例。
  • 自动扩展:微服务系统的负载均衡应该支持自动扩展。当系统负载增加时,可以自动添加新的服务实例以处理更多请求。这有助于应对流量波动和系统的横向扩展。
  • 故障转移:如果某个服务实例出现故障,负载均衡器应该自动将流量转移到其他健康的实例,以确保系统的可用性。
  • 会话粘附:在某些情况下,需要确保同一客户端的多个请求被路由到同一服务实例,以维护会话一致性。这称为会话粘附,一些负载均衡器支持此功能。

网关作用

  • 路由功能:网关可以根据目标地址的不同,选择最佳的路径将数据包从源网络路由到目标网络。它通过维护路由表来确定数据包的转发方向,并选择最优的路径。
  • 安全控制(统一认证授权):网关可以实施网络安全策略,对进出的数据包进行检查和过滤。它可以验证和授2权来自源网络的数据包,并阻止未经授权的访问。防火墙是一种常见的网关设备,用于过滤和保护网络免受恶意攻击和未经授权的访问。
  • 协议转换:不同网络使用不同的通信协议,网关可以进行协议转换,使得不同网络的设备可以互相通信。例如,例如将 HTTPS 协议转换成 HTTP 协议。
  • 网络地址转换(NAT):网关还可以执行网络地址转换,将内部网络使用的私有IP 地址转换为外部网络使用的公共 IP 地址,以实现多台计算机共享一个公共 IP 地址出去上网。

依赖及配置代码展示

@Bean
@Order(-1)  // 确保它比默认的错误处理器优先级高
public ErrorWebExceptionHandler myExceptionHandler() {
    return new JsonErrorWebExceptionHandler();
}
public class JsonErrorWebExceptionHandler implements ErrorWebExceptionHandler {
    @Override
    public Mono handle(ServerWebExchange exchange, Throwable ex) {
        exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY);
        // 设置响应体等
        return exchange.getResponse().writeWith(Mono.just(...));
    }
}
//跨域配置
@Configuration
public class CorsConfig {
    private static final String MAX_AGE = "18000L";
 
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            // 使用SpringMvc自带的跨域检测工具类判断当前请求是否跨域
            if (!CorsUtils.isCorsRequest(request)) {
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders = request.getHeaders();       // 获取请求头
            ServerHttpResponse response = ctx.getResponse();          // 获取响应对象
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();  // 获取请求方式对象
            HttpHeaders headers = response.getHeaders();           // 获取响应头
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());   // 把请求头中的请求源(协议+ip+端口)添加到响应头中(相当于yml中的allowedOrigins)
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());    // 允许被响应的方法(GET/POST等,相当于yml中的allowedMethods)
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); // 允许在请求中携带cookie(相当于yml中的allowCredentials)
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); // 允许在请求中携带的头信息(相当于yml中的allowedHeaders)
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);     // 本次跨域检测的有效期(单位毫秒,相当于yml中的maxAge)
            if (request.getMethod() == HttpMethod.OPTIONS) {      // 直接给option请求反回结果
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);         // 不是option请求则放行
        };
    }
 
}
//创建启动类
package com.atguigu.ceshi.apigateway;
@SpringBootApplication
@EnableDiscoveryClient  # 加上这个
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}
// pom.xml

    
    
        org.springframework.cloud
        spring-cloud-starter-gateway
    
    
    
        com.alibaba.cloud
        spring-cloud-starter-alibaba-nacos-discovery
    
//application.yml
server:
  port: 8888
spring:
  profiles:
    active: dev # 环境设置
  application:
    name: cloud-gateway #服务名
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
          - id:  payment_route #payment_route  路由的id,没有固定规则但要求唯一,建议配合服务名
            #uri: http://localhost:8001 #匹配后提供服务的路由地址
            #cloud-payment-service为eureka注册的服务名 lb是url的协议,表示启用Gateway的负载均衡功能
            uri: lb://cloud-payment-service #微服务提供服务的路由地址()
            predicates:
              - Path=/payment/get/**  #断言,路径相匹配的进行路由
 
          - id: payment_route2 #payment_route2  路由的id,没有固定规则但要求唯一,建议配合服务名
            #uri: http://localhost:8001 #匹配后提供服务的路由地址
            uri: lb://cloud-payment-service #匹配后提供服务的路由地址
            predicates:
              - Path=/payment/lb/**  #断言,路径相匹配的进行路由
@Configuration
public class GateWayConfig {
    /**
     * 配置了一个Id为route-name的路由规则,方访问地址http://localhost:8888
     * /guonei是会自动转发到地址
     */
    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_route_xwb", r -> r.path("/guonei").uri("http://news.baidu.com/guonei"))
          .build();
        return routes.build();
    }
/**
 * Gateway的Filter过滤连
 * 总的全局过滤器,档在所有微服务前面,进行校验
 */
package com.atguigu.guli.infrastructure.apigateway.filter;

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("全局过滤器");
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        //校验用户必须登录
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        if(antPathMatcher.match("/api/**/auth/**", path)) {
            List tokenList = request.getHeaders().get("token");

            //没有token
            if(null == tokenList) {
                ServerHttpResponse response = exchange.getResponse();
                return out(response);
            }

            //token校验失败
            Boolean isOK = JwtHelper.checkToken(tokenList.get(0));
            if(!isOK) {
                ServerHttpResponse response = exchange.getResponse();
                return out(response);
            }
        }

        //放行
        return chain.filter(exchange);
    }

    //定义当前过滤器的优先级,值越小,优先级越高
    @Override
    public int getOrder() {
        return 0;
    }

    private Mono out(ServerHttpResponse response) {

        JsonObject message = new JsonObject();
        message.addProperty("success", ResultCodeEnum.LOGIN_AUTH.getSuccess());
        message.addProperty("code", ResultCodeEnum.LOGIN_AUTH.getCode());
        message.addProperty("data", "");
        message.addProperty("message", ResultCodeEnum.LOGIN_AUTH.getMessage());
        byte[] bytes = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //输出http响应
        return response.writeWith(Mono.just(buffer));
    }
}
// 其他微服务
server:
  port: 8090
 
spring:
  application:
    name: testService01
  cloud:
    nacos:
      server-addr: 127.0.0.1:8082
      discovery:
        group: testGroup
        namespace: Dev
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
 
//其他微服务启动类
@SpringBootApplication
@EnableDiscoveryClient // nacos注册中心配置
public class TestServiceDemo01Application {
    public static void main(String[] args) {
        SpringApplication.run(TestServiceDemo01Application.class, args);
    }
}

gateway运行流程-草图

过滤流程

@Component
//@Order(-1) //过滤器的优先级,越小越高
public class AuthorizeFilter implements GlobalFilter , Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap queryParams = request.getQueryParams();
        //2.获取参数中的authorization参数
        String authorization = queryParams.getFirst("authorization");
        //3.判断参数值是否等于admin
        if("admin".equals(authorization)) {
            //4.是,放行
          return chain.filter(exchange);
        }
        //5.否,拦截
        //5.1设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

改造示例:

查看linux的nacos是否启动,如果没有启动先启动(nacos之前文档有)

一、新建gateway子工程

子工程

二、引入依赖

下面开始吐槽这个依赖引入的坑,很耗时间去解决,各种报错。

注意坑点(希望下次我遇到时,可以快速解决报错吧):

  • 1、gateway模块的pom不要去继承父工程的pom,父工程的pom依赖太多,极大可能会导致运行报错,新建gateway子工程后,pom父类就采用默认的spring-boot-starter-parent即可。
  • 2、在gateway自己的pom文件引入依赖,如下:

截图展示清晰

  • 3、在gateway自己的pom文件不要引用MVC的依赖包,不然会报错。
  • 4、网上根据报错查了很多解决方案,比如在pom文件里额外添加feign的依赖,或者更换cloud和springboot的版本,或者排除什么依赖,结果都会出现“解决当前问题,出现新的问题”。

如上解决方案,本人可行。(再次总结需要注意点:不要集成父工程的pom,不要引入MVC的依赖,只引入nacos-discovery和gateway依赖即可)。

三、改造gateway子模块

依赖问题解决后,就可以成功运行gateway模块了,前提是nacos已经开启了。然后开始改造gateway,使之与其他模块构成关联,具体如下:


  • 在gateway模块启动类上加上@EnableDiscoveryClient注解。
  • 修改yml配置文件,可以交给nacos管理,此处为了方便,直接写在本地yml配置里,如果不知道怎么使用nacos上的配置文件。接着说,修改yml文件后,结果如上图

此处配置将当前模块跑到nacos注册中心,然后开启gateway的注册中心路由功能

四、演示开启nacos注册中心路由功能效果

gateway可以通过routes和nacos的路由功能实现路由功能,现在展示一下nacos的路由功能效果。通过如下方法开启的路由功能:

gateway: discovery: locator: enabled: true #开启注册中心路由功能

五、演示自定义路由配置效果

上面第四点演示了默认通过注册中心实现网关路由的功能,下面第五点演示不通过第四点,而是自己通过routes配置自定义的路由策略,如下:

注意:若要使用自定义配置,则“不能开启注册中心的路由功能”,否则自定义的策略会失效,学习时给我坑惨了,百度也没找到问题,解决注释了开启注册中心的路由功能的配置,自定义的配置就生效了。

先写一个配置,再进行描述,配置如下:

yml

四个属性:

  • id:可以理解为是这组配置的一个id值,请保证他的唯一的,可以设置为和服务名一致。
  • uri:可以理解为是通过条件匹配之后需要路由到(跳转,重定向)到的新的服务地址。
  • predicates:可以理解为是编写条件,满足条件才进行uri。
  • filters:可以理解为是在路由前对请求的地址进行额外的其他操作,例如拼接或者裁减等。

六、启动主启动类

启动主类后就会看到 gateway被注册到nacos中了

然后就可以通过我们的gateway服务访问我们nacos中的服务了.示例到此就结束了.

常用方法

  • Forward Routing Filter:用于路由请求到后端服务。
  • LoadBalancerClient Filter:通过LoadBalancerClient执行负载均衡请求。
  • AddRequestHeader Filter:在请求中添加头信息。
  • AddRequestParameter Filter:在请求中添加查询参数。
  • RewritePath Filter:重写请求路径,用于修改请求的路径。
  • SetStatus Filter:设置HTTP响应状态码。
  • AddResponseHeader Filter:在响应中添加头信息。
  • Hystrix Filter:用于Hystrix断路器的支持。
  • WebSockets Filter:用于WebSocket代理。
  • ModifyResponseBody Filter:修改响应体内容。
  • PreserveHostHeader Filter:保留原始主机头信息。
  • RequestRateLimiter Filter:实现请求速率限制。

相关推荐

2023年最新微信小程序抓包教程(微信小程序 抓包)

声明:本公众号大部分文章来自作者日常学习笔记,部分文章经作者授权及其他公众号白名单转载。未经授权严禁转载。如需转载,请联系开百。请不要利用文章中的相关技术从事非法测试。由此产生的任何不良后果与文...

测试人员必看的软件测试面试文档(软件测试面试怎么说)

前言又到了毕业季,我们将会迎来许多需要面试的小伙伴,在这里呢笔者给从事软件测试的小伙伴准备了一份顶级的面试文档。1、什么是bug?bug由哪些字段(要素)组成?1)将在电脑系统或程序中,隐藏着的...

复活,视频号一键下载,有手就会,长期更新(2023-12-21)

视频号下载的话题,也算是流量密码了。但也是比较麻烦的问题,频频失效不说,使用方法也难以入手。今天,奶酪就来讲讲视频号下载的新方案,更关键的是,它们有手就会有用,最后一个方法万能。实测2023-12-...

新款HTTP代理抓包工具Proxyman(界面美观、功能强大)

不论是普通的前后端开发人员,还是做爬虫、逆向的爬虫工程师和安全逆向工程,必不可少会使用的一种工具就是HTTP抓包工具。说到抓包工具,脱口而出的肯定是浏览器F12开发者调试界面、Charles(青花瓷)...

使用Charles工具对手机进行HTTPS抓包

本次用到的工具:Charles、雷电模拟器。比较常用的抓包工具有fiddler和Charles,今天讲Charles如何对手机端的HTTS包进行抓包。fiddler抓包工具不做讲解,网上有很多fidd...

苹果手机下载 TikTok 旧版本安装包教程

目前苹果手机能在国内免拔卡使用的TikTok版本只有21.1.0版本,而AppStore是高于21.1.0版本,本次教程就是解决如何下载TikTok旧版本安装包。前期准备准备美区...

【0基础学爬虫】爬虫基础之抓包工具的使用

大数据时代,各行各业对数据采集的需求日益增多,网络爬虫的运用也更为广泛,越来越多的人开始学习网络爬虫这项技术,K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章,为实现从易到难全方位覆盖,特设【0基础学爬...

防止应用调试分析IP被扫描加固实战教程

防止应用调试分析IP被扫描加固实战教程一、概述在当今数字化时代,应用程序的安全性已成为开发者关注的焦点。特别是在应用调试过程中,保护应用的网络安全显得尤为重要。为了防止应用调试过程中IP被扫描和潜在的...

一文了解 Telerik Test Studio 测试神器

1.简介TelerikTestStudio(以下称TestStudio)是一个易于使用的自动化测试工具,可用于Web、WPF应用的界面功能测试,也可以用于API测试,以及负载和性能测试。Te...

HLS实战之Wireshark抓包分析(wireshark抓包总结)

0.引言Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接...

信息安全之HTTPS协议详解(加密方式、证书原理、中间人攻击 )

HTTPS协议详解(加密方式、证书原理、中间人攻击)HTTPS协议的加密方式有哪些?HTTPS证书的原理是什么?如何防止中间人攻击?一:HTTPS基本介绍:1.HTTPS是什么:HTTPS也是一个...

Fiddler 怎么抓取手机APP:抖音、小程序、小红书数据接口

使用Fiddler抓取移动应用程序(APP)的数据接口需要进行以下步骤:首先,确保手机与计算机连接在同一网络下。在计算机上安装Fiddler工具,并打开它。将手机的代理设置为Fiddler代理。具体方...

python爬虫教程:教你通过 Fiddler 进行手机抓包

今天要说说怎么在我们的手机抓包有时候我们想对请求的数据或者响应的数据进行篡改怎么做呢?我们经常在用的手机手机里面的数据怎么对它抓包呢?那么...接下来就是学习python的正确姿势我们要用到一款强...

Fiddler入门教程全家桶,建议收藏

学习Fiddler工具之前,我们先了解一下Fiddler工具的特点,Fiddler能做什么?如何使用Fidder捕获数据包、修改请求、模拟客户端向服务端发送请求、实施越权的安全性测试等相关知识。本章节...

fiddler如何抓取https请求实现手机抓包(100%成功解决)

一、HTTP协议和HTTPS协议。(1)HTTPS协议=HTTP协议+SSL协议,默认端口:443(2)HTTP协议(HyperTextTransferProtocol):超文本传输协议。默认...