Spring Cloud Gateway编码实现任意地址跳转

这篇具有很好参考价值的文章主要介绍了Spring Cloud Gateway编码实现任意地址跳转。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 作为《Spring Cloud Gateway实战》系列的第十四篇,本文会继续发掘Spring Cloud Gateway的潜力,通过编码体验操控网关的乐趣,开发出一个实用的功能:让Spring Cloud Gateway应用在收到请求后,可以按照业务的需要跳转到任意的地址去

一般路由规则

  • 先来看一个普通的路由规则,如下所示,意思是将所有/hello/**的请求转发到http://127.0.0.1:8082这个地址去:
spring:
  application:
    name: hello-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:8082
          predicates:
          - Path=/hello/**
  • 上述规则的功能如下图所示,假设这就是生产环境的样子,192.168.50.99:8082是提供服务的后台应用:
    Spring Cloud Gateway编码实现任意地址跳转

特殊规则

  • 以上是常规情况,但也有些特殊情况,要求SpringCloud Gateway把浏览器的请求转发到不同的服务上去
  • 如下图所示,在之前的环境中增加了另一个服务(即蓝色块),假设蓝色服务代表测试环境
    Spring Cloud Gateway编码实现任意地址跳转
  • 浏览器发起的/hello/str请求中,如果header中带有tag-test-user,并且值等于true,此时要求SpringCloud Gateway把这个请求转发到测试环境
  • 如果浏览器的请求header中没有tag-test-user,SpringCloud Gateway需要像以前那样继续转发到192.168.50.99:8082
  • 很明显,上述需求难以通过配置来实现,因为转发的地址和转发逻辑都是围绕业务逻辑来定制的,这也就是本篇的目标:对同一个请求path,可以通过编码转发到不同的地方去
  • 实现上述功能的具体做法是:自定义过滤器

设计

  • 编码之前先设计,把关键点想清楚再动手
  • 今天咱们要开发一个SpringCloud Gateway应用,里面新增一个自定义过滤器
  • 实现这个功能需要三个知识点作为基础,也就是说,您会通过本篇实战掌握以下知识点:
  1. 自定义过滤器
  2. 自定义过滤器的配置参数和bean的映射
  3. 编码构造Route实例
  • 用思维导图将具体工作内容展开,如下图所示,咱们就按部就班的实现吧:
    Spring Cloud Gateway编码实现任意地址跳转

源码下载

  • 本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本篇的源码在spring-cloud-tutorials文件夹下,如下图红框所示:
    Spring Cloud Gateway编码实现任意地址跳转- spring-cloud-tutorials内部有多个子项目,本篇的源码在gateway-dynamic-route文件夹下,如下图红框所示:
    Spring Cloud Gateway编码实现任意地址跳转

编码

  • 新建名为gateway-dynamic-route的maven工程,其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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-tutorials</artifactId>
        <groupId>com.bolingcavalry</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gateway-dynamic-route</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.bolingcavalry</groupId>
            <artifactId>common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- 如果父工程不是springboot,就要用以下方式使用插件,才能生成正常的jar -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.bolingcavalry.gateway.GatewayDynamicRouteApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  • 启动类是普通的SpringBoot启动类:
package com.bolingcavalry.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayDynamicRouteApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayDynamicRouteApplication.class,args);
    }
}
  • 接下来是本篇的核心,自定义过滤器类,代码中已经添加了详细的注释,有几处要注意的地方稍后会提到:
package com.bolingcavalry.gateway.filter;

import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

@Component
@Slf4j
public class BizLogicRouteGatewayFilterFactory extends AbstractGatewayFilterFactory<BizLogicRouteGatewayFilterFactory.BizLogicRouteConfig> {

    private static final String TAG_TEST_USER = "tag-test-user";

    public BizLogicRouteGatewayFilterFactory() {
        super(BizLogicRouteConfig.class);
    }

    @Override
    public GatewayFilter apply(BizLogicRouteConfig config) {

        return (exchange, chain) -> {
            // 本次的请求对象
            ServerHttpRequest request =  exchange.getRequest();

            // 调用方请求时的path
            String rawPath = request.getURI().getRawPath();

            log.info("rawPath [{}]", rawPath);

            // 请求头
            HttpHeaders headers = request.getHeaders();

            // 请求方法
            HttpMethod httpMethod = request.getMethod();

            // 请求参数
            MultiValueMap<String, String> queryParams = request.getQueryParams();

            // 这就是定制的业务逻辑,isTestUser等于ture代表当前请求来自测试用户,需要被转发到测试环境
            boolean isTestUser = false;

            // 如果header中有tag-test-user这个key,并且值等于true(不区分大小写),
            // 就认为当前请求是测试用户发来的
            if (headers.containsKey(TAG_TEST_USER)) {
                String tageTestUser = headers.get(TAG_TEST_USER).get(0);

                if ("true".equalsIgnoreCase(tageTestUser)) {
                    isTestUser = true;
                }
            }

            URI uri;

            if (isTestUser) {
                log.info("这是测试用户的请求");
                // 从配置文件中得到测试环境的uri
                uri = UriComponentsBuilder.fromHttpUrl(config.getTestEnvUri() + rawPath).queryParams(queryParams).build().toUri();
            } else {
                log.info("这是普通用户的请求");
                // 从配置文件中得到正式环境的uri
                uri = UriComponentsBuilder.fromHttpUrl(config.getProdEnvUri() + rawPath).queryParams(queryParams).build().toUri();
            }

            // 生成新的Request对象,该对象放弃了常规路由配置中的spring.cloud.gateway.routes.uri字段
            ServerHttpRequest serverHttpRequest = request.mutate().uri(uri).method(httpMethod).headers(httpHeaders -> httpHeaders = httpHeaders).build();

            // 取出当前的route对象
            Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
            //从新设置Route地址
            Route newRoute =
                    Route.async().asyncPredicate(route.getPredicate()).filters(route.getFilters()).id(route.getId())
                            .order(route.getOrder()).uri(uri).build();
            // 放回exchange中
            exchange.getAttributes().put(GATEWAY_ROUTE_ATTR,newRoute);

            // 链式处理,交给下一个过滤器
            return chain.filter(exchange.mutate().request(serverHttpRequest).build());
        };
    }

    /**
     * 这是过滤器的配置类,配置信息会保存在此处
     */
    @Data
    @ToString
    public static class BizLogicRouteConfig {
        // 生产环境的服务地址
        private String prodEnvUri;

        // 测试环境的服务地址
        private String testEnvUri;
    }
}
  • 上述代码中要注意的地方如下:
  1. BizLogicRouteConfig是过滤器的配置类,可以在使用过滤器时在配置文件中配置prodEnvUri和testEnvUri的值,在代码中可以通过这两个字段取得配置值
  2. 过滤器的工厂类名为BizLogicRouteGatewayFilterFactory,按照规则,过滤器的名字是BizLogicRoute
  3. 在apply方法中,重新创建ServerHttpRequest和Route对象,它们的参数可以按照业务需求随意设置,然后再将这两个对象设置给SpringCloud gateway的处理链中,接下来,处理链上的其他过滤拿到的就是新的ServerHttpRequest和Route对象了

配置

  • 假设生产环境地址是http://127.0.0.1:8082,测试环境地址是http://127.0.0.1:8087,整个SpringCloud Gateway应用的配置文件如下,可见使用了刚刚创建的过滤器,并且为此过滤器配置了两个参数:
server:
  #服务端口
  port: 8086
spring:
  application:
    name: gateway-dynamic-route
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://0.0.0.0:8082
          predicates:
          - Path=/hello/**
          filters:
            - name: BizLogicRoute
              args:
                prodEnvUri: http://127.0.0.1:8082
                testEnvUri: http://127.0.0.1:8087
  • 至此,编码完成了,启动这个服务

开发和启动后台服务,模拟生产和测试环境

  • 接下来开始验证功能是否生效,咱们要准备两个后台服务:
  1. 模拟生产环境的后台服务是provider-hello,监听端口是8082,其/hello/str接口的返回值是Hello World, 2021-12-12 10:53:09
  2. 模拟测试环境的后台服务是provider-for-test-user,监听端口是8087,其/hello/str接口的返回值是Hello World, 2021-12-12 10:57:11 (from test enviroment)(和生产环境相比,返回内容多了个(from test enviroment)),对应Controller参考如下:
package com.bolingcavalry.provider.controller;

import com.bolingcavalry.common.Constants;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

@RestController
@RequestMapping("/hello")
public class Hello {

    private String dateStr(){
        return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
    }

    /**
     * 返回字符串类型
     * @return
     */
    @GetMapping("/str")
    public String helloStr() {
        return Constants.HELLO_PREFIX + ", " + dateStr() + " (from test enviroment)";
    }
}
  • 以上两个服务,对应的代码都在我的Github仓库中,如下图红框所示:
    Spring Cloud Gateway编码实现任意地址跳转
  • 启动gateway-dynamic-routeprovider-helloprovider-for-test-user服务
  • 此时,SpringCloud gateway应用和两个后台服务都启动完成,情况如下图,接下来验证刚才开发的过滤器能不能像预期那样转发:
    Spring Cloud Gateway编码实现任意地址跳转

验证

  • 用postman工具向gateway-dynamic-route应用发起一次请求,返回值如下图红框所示,证明这是provider-hello的响应,看来咱们的请求已经正常到达:
    Spring Cloud Gateway编码实现任意地址跳转
  • 再发送一次请求,如下图,这次在header中加入键值对,得到的结果是provider-for-test-user的响应
    Spring Cloud Gateway编码实现任意地址跳转
  • 至此,过滤器的开发和验证已经完成,通过编码,可以把外部请求转发到任何咱们需要的地址去,并且支持参数配置,这个过滤器还有一定的可配置下,减少了硬编码的比率,如果您正在琢磨如何深度操控SpringCloud Gateway,希望本文能给您一些参考;

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...文章来源地址https://www.toymoban.com/news/detail-501817.html

到了这里,关于Spring Cloud Gateway编码实现任意地址跳转的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud Gateway集成Nacos实现负载均衡

    💡Nacas可以用于实现Spring Cloud Gateway中网关动态路由功能,也可以基于Nacos来实现对后端服务的负载均衡,前者利用Nacos配置中心功能,后者利用Nacos服务注册功能。 接下来我们来看下Gateway集成Nacos实现负载均衡的架构图 一. 环境准备 1. 版本环境 Jdk: java.version1.8/java.version Spr

    2024年02月10日
    浏览(60)
  • Spring Cloud 之 Sentinel简介与GATEWAY整合实现

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 熔断 微服务架构的系统通常会包含

    2024年02月19日
    浏览(42)
  • 基于Spring-cloud-gateway实现全局日志记录

    最近项目在线上运行出现了一些难以复现的bug需要定位相应api的日志,通过nginx提供的api请求日志难以实现,于是在gateway通过全局过滤器记录api请求日志。 接受到用户请求后,经过全局过滤器,检验是否开启相应的日志配置及相应的黑白名单配置 在gateway前置处理如记录当前

    2024年02月11日
    浏览(61)
  • Spring Cloud Gateway + Nacos 实现服务上下线无缝切换

    大家好,我是不才陈某~ 最近知识星球的球友在学习星球中的《精尽Spring Cloud Alibaba》专栏提到一个问题,相信也有很多人在线上环境遇到过,或许也因此被批过:一个集群中有某个服务突然下线,但是网关还是会去请求这个实例,所以线上就报错了,报错信息如下图: 究其

    2024年02月15日
    浏览(44)
  • Spring Cloud - 手写 Gateway 源码,实现自定义局部 FilterFactory

    目录 一、FilterFactory 分析 1.1、前置知识 1.2、分析源码 1.2.1、整体分析 1.2.2、源码分析 1.3、手写源码 1.3.1、基础框架 1.3.2、实现自定义局部过滤器 1.3.3、加参数的自定义局部过滤器器 前面的学习我们知道,GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服

    2024年02月03日
    浏览(42)
  • Spring Cloud Gateway 整合 sentinel 实现流控熔断

            在微服务架构中,网关层可以屏蔽外部服务直接对内部服务进行调用,对内部服务起到隔离保护的作用,网关限流,顾名思义,就是通过网关层对服务进行限流,从而达到保护后端服务的作用。         Sentinel 从 1.6.0 版本开始就提供了 Spring Cloud Gateway 的适配

    2023年04月23日
    浏览(47)
  • spring-cloud-starter-gateway-mvc的网关实现

    最近,我也一直在使用SpringCloudGateway开发我们自己的网关产品。根据我对官网文档:https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-mvc.html 的理解,内容如下: SpringCloudGateway的默认底层依赖项是SpringWebflux。我们知道Spring Webflux是异步和响应式编程,并且编程范

    2024年01月17日
    浏览(47)
  • 【SpringCloud】11、Spring Cloud Gateway使用Sentinel实现服务限流

    1、关于 Sentinel Sentinel 是阿里巴巴开源的一个流量防卫防护组件,可以为微服务架构提供强大的流量防卫能力,包括流量控制、熔断降级等功能。Spring Cloud Gateway 与 Sentinel 结合,可以实现强大的限流功能。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近

    2024年02月01日
    浏览(57)
  • Spring Cloud Gateway + Oauth2 实现统一认证和鉴权!

    micro-oauth2-gateway:网关服务,负责请求转发和鉴权功能,整合Spring Security+Oauth2; micro-oauth2-auth:Oauth2认证服务,负责对登录用户进行认证,整合Spring Security+Oauth2; micro-oauth2-api:受保护的API服务,用户鉴权通过后可以访问该服务,不整合Spring Security+Oauth2。 我们首先来搭建认

    2024年01月16日
    浏览(62)
  • Spring Cloud Gateway 整合OAuth2.0 实现统一认证授权

    Spring Cloud Gateway 整合OAuth2.0 实现统一认证授权 GateWay——向其他服务传递参数数据 https://blog.csdn.net/qq_38322527/article/details/126530849 @EnableAuthorizationServer Oauth2ServerConfig 验证签名 网关服务需要RSA的公钥来验证签名是否合法,所以认证服务需要有个接口把公钥暴露出来 接下来搭建网

    2024年02月13日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包