SA实战 ·《SpringCloud Alibaba实战》第14章-服务网关:SpringCloud Gateway核心技术 下

简介: SA实战 ·《SpringCloud Alibaba实战》第14章-服务网关:SpringCloud Gateway核心技术

自定义断言

SpringCloud Gateway支持自定义断言功能,我们可以在具体业务中,基于SpringCloud Gateway自定义特定的断言功能。

自定义断言概述

SpringCloud Gateway虽然提供了多种内置的断言功能,但是在某些场景下无法满足业务的需要,此时,我们就可以基于SpringCloud Gateway自定义断言功能,以此来满足我们的业务场景。

实现自定义断言

这里,我们基于SpringCloud Gateway实现断言功能,实现后的效果是在服务网关的application.yml文件中的spring.cloud.gateway.routes节点下的- id: user-gateway下面进行如下配置。

spring:
  cloud:
    gateway:
      routes:
        - id: user-gateway
          uri: http://localhost:8060
          order: 1
          predicates:
            - Path=/server-user/**
            - Name=binghe
          filters:
            - StripPrefix=1

通过服务网关访问用户微服务时,只有在访问的链接后面添加?name=binghe参数时才能正确访问用户微服务。

(1)在网关服务shop-gateway中新建io.binghe.shop.predicate包,在包下新建NameRoutePredicateConfig类,主要定义一个Spring类型的name成员变量,用来接收配置文件中的参数,源码如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 接收配置文件中的参数
 */
@Data
public class NameRoutePredicateConfig implements Serializable {
    private static final long serialVersionUID = -3289515863427972825L;
    private String name;
}

(2)实现自定义断言时,需要新建类继承org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory类,在io.binghe.shop.predicate包下新建NameRoutePredicateFactory类,继承org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory类,并覆写相关的方法,源码如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 自定义断言功能
 */
@Component
public class NameRoutePredicateFactory extends AbstractRoutePredicateFactory<NameRoutePredicateConfig> {
    public NameRoutePredicateFactory() {
        super(NameRoutePredicateConfig.class);
    }
    @Override
    public Predicate<ServerWebExchange> apply(NameRoutePredicateConfig config) {
        return (serverWebExchange)->{
            String name = serverWebExchange.getRequest().getQueryParams().getFirst("name");
            if (StringUtils.isEmpty(name)){
                name = "";
            }
            return name.equals(config.getName());
        };
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }
}

(3)在服务网关的application.yml文件中的spring.cloud.gateway.routes节点下的- id: user-gateway下面进行如下配置。

spring:
  cloud:
    gateway:
      routes:
        - id: user-gateway
          uri: http://localhost:8060
          order: 1
          predicates:
            - Path=/server-user/**
            - Name=binghe
          filters:
            - StripPrefix=1

(4)分别启动用户微服务与网关服务,在浏览器中输入http://localhost:10001/server-user/user/get/1001,如下所示。

image.gif图片.png


可以看到,在浏览器中输入http://localhost:10001/server-user/user/get/1001,无法获取到用户信息。

(5)在浏览器中输入http://localhost:10001/server-user/user/get/1001?name=binghe,如下所示。

image.gif图片.png


可以看到,在访问链接后添加?name=binghe参数后,能够正确获取到用户信息。

至此,我们实现了自定义断言功能。

网关过滤器

过滤器可以在请求过程中,修改请求的参数和响应的结果等信息。在生命周期的角度总体上可以分为前置过滤器(Pre)和后置过滤器(Post)。在实现的过滤范围角度可以分为局部过滤器(GatewayFilter)和全局过滤器(GlobalFilter)。局部过滤器作用的范围是某一个路由,全局过滤器作用的范围是全部路由。

  • Pre前置过滤器:在请求被网关路由之前调用,可以利用这种过滤器实现认证、鉴权、路由等功能,也可以记录访问时间等信息。
  • Post后置过滤器:在请求被网关路由到微服务之后执行。可以利用这种过滤器修改HTTP的响应Header信息,修改返回的结果数据(例如对于一些敏感的数据,可以在此过滤器中统一处理后返回),收集一些统计信息等。
  • 局部过滤器(GatewayFilter):也可以称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由分组。
  • 全局过滤器(GlobalFilter):这种过滤器主要作用于所有的路由。

局部过滤器

局部过滤器又称为网关过滤器,这种过滤器主要是作用于单一路由或者某个路由分组。

局部过滤器概述

在SpringCloud Gateway中内置了很多不同类型的局部过滤器,主要如下所示。

图片.pngimage.gif


演示内部过滤器

演示内部过滤器时,我们为原始请求添加一个名称为IP的Header,值为localhost,并添加一个名称为name的参数,参数值为binghe。同时修改响应的结果状态,将结果状态修改为1001。

(1)在服务网关的application.yml文件中的spring.cloud.gateway.routes节点下的- id: user-gateway下面进行如下配置。

spring:
  cloud:
    gateway:
      routes:
        - id: user-gateway
          uri: http://localhost:8060
          order: 1
          predicates:
            - Path=/server-user/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=IP,localhost
            - AddRequestParameter=name,binghe
            - SetStatus=1001

(2)在用户微服务的io.binghe.shop.user.controller.UserController类中新增apiFilter1()方法,如下所示。

@GetMapping(value = "/api/filter1")
public String apiFilter1(HttpServletRequest request, HttpServletResponse response){
    log.info("访问了apiFilter1接口");
    String ip = request.getHeader("IP");
    String name = request.getParameter("name");
    log.info("ip = " + ip + ", name = " + name);
    return "apiFilter1";
}

可以看到,在新增加的apiFilter1()方法中,获取到新增加的Header与参数,并将获取出来的参数与Header打印出来。并且方法返回的是字符串apiFilter1。

(3)分别启动用户微服务与网关服务,在浏览器中输入http://localhost:10001/server-user/user/api/filter1,如下所示。

图片.png


此时,查看浏览器中的响应状态码,如下所示。

图片.png


可以看到,此时的状态码已经被修改为1001。

接下来,查看下用户微服务的控制台输出的信息,发现在输出的信息中存在如下数据。

访问了apiFilter1接口
ip = localhost, name = binghe

说明使用SpringCloud Gateway的内置过滤器成功为原始请求添加了一个名称为IP的Header,值为localhost,并添加了一个名称为name的参数,参数值为binghe。同时修改了响应的结果状态,将结果状态修改为1001,符合预期效果。

自定义局部过滤器

这里,我们基于SpringCloud Gateway自定义局部过滤器实现是否开启灰度发布的功能,整个实现过程如下所示。

(1)在服务网关的application.yml文件中的spring.cloud.gateway.routes节点下的- id: user-gateway下面进行如下配置。

spring:
  cloud:
    gateway:
      routes:
        - id: user-gateway
          uri: http://localhost:8060
          order: 1
          predicates:
            - Path=/server-user/**
          filters:
            - StripPrefix=1
            - Grayscale=true

(2)在网关服务模块shop-gateway中新建io.binghe.shop.filter包,在包下新建GrayscaleGatewayFilterConfig类,用于接收配置中的参数,如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 接收配置参数
 */
@Data
public class GrayscaleGatewayFilterConfig implements Serializable {
    private static final long serialVersionUID = 983019309000445082L;
    private boolean grayscale;
}

(3)在io.binghe.shop.filter包下GrayscaleGatewayFilterFactory类,继承org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory类,主要是实现自定义过滤器,模拟实现灰度发布。代码如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 自定义过滤器模拟实现灰度发布
 */
@Component
public class GrayscaleGatewayFilterFactory extends AbstractGatewayFilterFactory<GrayscaleGatewayFilterConfig> {
    public GrayscaleGatewayFilterFactory(){
        super(GrayscaleGatewayFilterConfig.class);
    }
    @Override
    public GatewayFilter apply(GrayscaleGatewayFilterConfig config) {
        return (exchange, chain) -> {
            if (config.isGrayscale()){
                System.out.println("开启了灰度发布功能...");
            }else{
                System.out.println("关闭了灰度发布功能...");
            }
            return chain.filter(exchange);
        };
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("grayscale");
    }
}

(4)分别启动用户微服务和服务网关,在浏览器中输入http://localhost:10001/server-user/user/get/1001,如下所示。

image.gif

图片.png

可以看到,通过服务网关正确访问到了用户微服务,并正确获取到了用户信息。

接下来,查看下服务网关的终端,发现已经成功输出了如下信息。

开启了灰度发布功能...

说明正确实现了自定义的局部过滤器。

全局过滤器

全局过滤器是一系列特殊的过滤器,会根据条件应用到所有路由中。

全局过滤器概述

在SpringCloud Gateway中内置了多种不同的全局过滤器,如下所示。

image.gif

图片.png

演示全局过滤器

(1)在服务网关模块shop-gateway模块下的io.binghe.shop.config包下新建GatewayFilterConfig类,并在类中配置几个全局过滤器,如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 网关过滤器配置
 */
@Configuration
@Slf4j
public class GatewayFilterConfig {
    @Bean
    @Order(-1)
    public GlobalFilter globalFilter() {
        return (exchange, chain) -> {
            log.info("执行前置过滤器逻辑");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("执行后置过滤器逻辑");
            }));
        };
    }
}

注意:@Order注解中的数字越小,执行的优先级越高。

(2)启动用户微服务与服务网关,在浏览器中访问http://localhost:10001/server-user/user/get/1001,如下所示。

图片.png


在服务网关终端输出如下信息。

执行前置过滤器逻辑
执行后置过滤器逻辑

说明我们演示的全局过滤器生效了。

自定义全局过滤器

SpringCloud Gateway内置了很多全局过滤器,一般情况下能够满足实际开发需要,但是对于某些特殊的业务场景,还是需要我们自己实现自定义全局过滤器。

这里,我们就模拟实现一个获取客户端访问信息,并统计访问接口时长的全局过滤器。

(1)在网关服务模块shop-order的io.binghe.shop.filter包下,新建GlobalGatewayLogFilter类,实现org.springframework.cloud.gateway.filter.GlobalFilter接口和org.springframework.core.Ordered接口,代码如下所示。

/**
 * @author binghe
 * @version 1.0.0
 * @description 自定义全局过滤器,模拟实现获取客户端信息并统计接口访问时长
 */
@Slf4j
@Component
public class GlobalGatewayLogFilter implements GlobalFilter, Ordered {
    /**
     * 开始访问时间
     */
    private static final String BEGIN_VISIT_TIME = "begin_visit_time";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //先记录下访问接口的开始时间
        exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);
            if (beginVisitTime != null){
                log.info("访问接口主机: " + exchange.getRequest().getURI().getHost());
                log.info("访问接口端口: " + exchange.getRequest().getURI().getPort());
                log.info("访问接口URL: " + exchange.getRequest().getURI().getPath());
                log.info("访问接口URL参数: " + exchange.getRequest().getURI().getRawQuery());
                log.info("访问接口时长: " + (System.currentTimeMillis() - beginVisitTime) + "ms");
            }
        }));
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

上述代码的实现逻辑还是比较简单的,这里就不再赘述了。

(2)启动用户微服务与网关服务,在浏览器中输入http://localhost:10001/server-user/user/api/filter1?name=binghe,如下所示。

图片.png


接下来,查看服务网关的终端日志,可以发现已经输出了如下信息。

访问接口主机: localhost
访问接口端口: 10001
访问接口URL: /server-user/user/api/filter1
访问接口URL参数: name=binghe
访问接口时长: 126ms

说明我们自定义的全局过滤器生效了。

网关熔断机制

其实熔断机制在《SA实战 ·《SpringCloud Alibaba实战》第13章-服务网关:项目整合SpringCloud Gateway网关》一文中就基于SpringCloud Gateway整合Sentinel实现了。大家可以参见《SA实战 ·《SpringCloud Alibaba实战》第13章-服务网关:项目整合SpringCloud Gateway网关》一文。

注意:整个实战案例基于SpringCloud Alibaba技术栈实现,所以,整个案例专栏也是偏向于使用SpringCloud Alibaba技术栈的。

相关文章
|
11月前
|
应用服务中间件 网络安全 数据安全/隐私保护
网关服务器配置指南:实现自动DHCP地址分配、HTTP服务和SSH无密码登录。
哇哈哈,道具都准备好了,咱们的魔术秀就要开始了。现在,你的网关服务器已经魔法满满,自动分配IP,提供网页服务,SSH登录如入无人之境。而整个世界,只会知道效果,不会知道是你在幕后操控一切。这就是真正的数字世界魔法师,随手拈来,手到擒来。
544 14
|
负载均衡 Dubbo Java
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
|
存储 监控 安全
工业物联网关应用:PLC数据通过智能网关上传阿里云实战
本文介绍如何使用智能网关将工厂PLC数据传输至阿里云平台,适合中小企业远程监控设备状态。硬件准备包括三菱FX3U PLC、4G智能网关和24V电源。接线步骤涵盖PLC编程口与网关连接、运行状态检测及天线电源接入。配置过程涉及通讯参数、阿里云对接和数据点映射。PLC程序关键点包括数据上传触发和温度值处理。阿里云平台操作包含实时数据查看、数据可视化和规则引擎设置。最后提供常见故障排查表和安全建议,确保系统稳定运行。
1434 1
|
人工智能 SpringCloudAlibaba 自然语言处理
SpringCloud Alibaba AI整合DeepSeek落地AI项目实战
在现代软件开发领域,微服务架构因其灵活性、可扩展性和模块化特性而受到广泛欢迎。微服务架构通过将大型应用程序拆分为多个小型、独立的服务,每个服务运行在其独立的进程中,服务与服务间通过轻量级通信机制(通常是HTTP API)进行通信。这种架构模式有助于提升系统的可维护性、可扩展性和开发效率。
5331 2
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
3180 13
Spring Cloud Alibaba:一站式微服务解决方案
|
SpringCloudAlibaba 负载均衡 Dubbo
【SpringCloud Alibaba系列】Dubbo高级特性篇
本章我们介绍Dubbo的常用高级特性,包括序列化、地址缓存、超时与重试机制、多版本、负载均衡。集群容错、服务降级等。
2044 7
【SpringCloud Alibaba系列】Dubbo高级特性篇
|
存储 SpringCloudAlibaba Java
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论。
【SpringCloud Alibaba系列】一文全面解析Zookeeper安装、常用命令、JavaAPI操作、Watch事件监听、分布式锁、集群搭建、核心理论
|
SpringCloudAlibaba JavaScript Dubbo
【SpringCloud Alibaba系列】Dubbo dubbo-admin安装教程篇
本文介绍了 Dubbo-Admin 的安装和使用步骤。Dubbo-Admin 是一个前后端分离的项目,前端基于 Vue,后端基于 Spring Boot。安装前需确保开发环境(Windows 10)已安装 JDK、Maven 和 Node.js,并在 Linux CentOS 7 上部署 Zookeeper 作为注册中心。
4168 1
【SpringCloud Alibaba系列】Dubbo dubbo-admin安装教程篇
|
SpringCloudAlibaba Dubbo Java
【SpringCloud Alibaba系列】Dubbo基础入门篇
Dubbo是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。
【SpringCloud Alibaba系列】Dubbo基础入门篇
|
人工智能 安全 Java
AI 时代:从 Spring Cloud Alibaba 到 Spring AI Alibaba
本次分享由阿里云智能集团云原生微服务技术负责人李艳林主讲,主题为“AI时代:从Spring Cloud Alibaba到Spring AI Alibaba”。内容涵盖应用架构演进、AI agent框架发展趋势及Spring AI Alibaba的重磅发布。分享介绍了AI原生架构与传统架构的融合,强调了API优先、事件驱动和AI运维的重要性。同时,详细解析了Spring AI Alibaba的三层抽象设计,包括模型支持、工作流智能体编排及生产可用性构建能力,确保安全合规、高效部署与可观测性。最后,结合实际案例展示了如何利用私域数据优化AI应用,提升业务价值。
1666 4

热门文章

最新文章