欢迎访问我的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-gatewaycloud:gateway:routes:- id: path_routeuri: http://127.0.0.1:8082predicates:- Path=/hello/**
  • 上述规则的功能如下图所示,假设这就是生产环境的样子,192.168.50.99:8082是提供服务的后台应用:

特殊规则

  • 以上是常规情况,但也有些特殊情况,要求SpringCloud 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实例
  • 用思维导图将具体工作内容展开,如下图所示,咱们就按部就班的实现吧:

源码下载

  • 本篇实战中的完整源码可在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-tutorials内部有多个子项目,本篇的源码在gateway-dynamic-route文件夹下,如下图红框所示:

编码

  • 新建名为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);}@Overridepublic GatewayFilter apply(BizLogicRouteConfig config) {return (exchange, chain) -> {// 本次的请求对象ServerHttpRequest request =  exchange.getRequest();// 调用方请求时的pathString 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("这是测试用户的请求");// 从配置文件中得到测试环境的uriuri = UriComponentsBuilder.fromHttpUrl(config.getTestEnvUri() + rawPath).queryParams(queryParams).build().toUri();} else {log.info("这是普通用户的请求");// 从配置文件中得到正式环境的uriuri = 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@ToStringpublic 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-routecloud:gateway:routes:- id: path_routeuri: http://0.0.0.0:8082predicates:- Path=/hello/**filters:- name: BizLogicRouteargs:prodEnvUri: http://127.0.0.1:8082testEnvUri: 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仓库中,如下图红框所示:
  • 启动gateway-dynamic-route、provider-hello、provider-for-test-user服务
  • 此时,SpringCloud gateway应用和两个后台服务都启动完成,情况如下图,接下来验证刚才开发的过滤器能不能像预期那样转发:

验证

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

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

Spring Cloud Gateway编码实现任意地址跳转相关推荐

  1. 网关 翻译版本 spring cloud gateway

    Spring Cloud Gateway 官网原文地址 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html ...

  2. Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!

    前一篇文章介绍了Spring Cloud Gateway的一些基础知识点,今天陈某就来唠一唠网关层面如何做限流? 文章目录如下: 网关如何限流? Spring Cloud Gateway本身自带的限流 ...

  3. Spring Cloud Gateway 整合阿里 Sentinel网关限流实战

    文章目录如下: 网关如何限流? Spring Cloud Gateway本身自带的限流实现,过滤器是RequestRateLimiterGatewayFilterFactory,不过这种上不了台面的就 ...

  4. SpringCloud-07-新一代路由网关Spring Cloud Gateway

    服务网关Gateway 1. 概述简介 1. SpringCloud Gateway是什么? 服务网关还可以用Zuul网关,但是Zuul网关由于一些维护问题,所以这里我们学习Gateway网关,Spr ...

  5. Spring Cloud Gateway 远程代码执行漏洞(CVE-2022-22947)

    引言   Spring Cloud Gateway是基于Spring Framework和Spring Boot构建的API网关,它旨在为微服务架构提供一种简单.有效.统一的API路由管理方式.    ...

  6. Spring Cloud Gateway 3.1.3最新版中文手册官网2022

    Spring Cloud Gateway 3.1.3 该项目提供了一个库,用于在 Spring WebFlux 之上构建 API 网关.Spring Cloud Gateway 旨在提供一种简单而有效 ...

  7. 微服务网关spring cloud gateway入门详解

    1.API网关 API 网关是一个处于应用程序或服务( REST API 接口服务)之前的系统,用来管理授权.访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的 ...

  8. 【Spring Cloud Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权

    一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间这里只贴出关键部分代码的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证 ...

  9. 熬夜肝了这篇Spring Cloud Gateway的功能及综合使用

    前言 SpringCloud 是微服务中的翘楚,最佳的落地方案. Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul.网关通常在 ...

  10. Spring Cloud(10)——新一代网关Spring Cloud Gateway

    文章目录 Spring Cloud(10)--新一代网关Spring Cloud Gateway 1.背景知识--API网关 2.Spring Cloud Gateway 详细概述 3.Spring ...

最新文章

  1. SSM高级整合项目实战
  2. PHP explode() 函数
  3. python画剖面图_如何创建Matplotlib图形与图像和剖面图相匹配?
  4. 听说过代码洁癖,还没听说过有 Bug 洁癖的?
  5. git 本地分支与远程分支关联的一种方法
  6. [USACO07NOV]牛继电器Cow Relays
  7. ❤️ 爆肝一个月!JAVA零基础入门总结(上)❤️
  8. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 22丨页面推荐【难度中等】​
  9. 作者:​光亮(1982-),男,博士,华为技术有限公司高级标准经理。
  10. Facebook入局视频会议,日活用户超3亿的Zoom股价应声下跌,Zoom为何不扛打?
  11. 使用jQuery获取表格内容、:nth-child() 选择器用法
  12. Linus送出圣诞礼物:发布Linux 4.20,超35万行代码
  13. Blend 动画 模板
  14. win10卸载电脑管家就蓝屏_新电脑WIN10出现蓝屏 系统重装也不行
  15. 纯前端控件集 WijmoJS 2018V2发布,提供可视化设计器,在React、Vue和Angular中的更易用...
  16. 我,第一次做项目经理,干赔了
  17. 关于VM14中安装win 10遇到的小问题
  18. windows ping不通虚拟机ip地址
  19. Go语言安装配置运行
  20. 何同学采访苹果CEO库克上热搜,网友表示自愧不如

热门文章

  1. Neo4j图数据库高级应用系列 / 服务器扩展指南 APOC - apoc.periodic.iterate()过程在4.0版本中的重大变化
  2. 区块链自由意志数据隐私安全
  3. 联想 ThinkBook 15 LLI 蓝屏恢复
  4. RocketMQ Message相关命令【实战笔记】
  5. STM32F103驱动四位共阳极数码管程序
  6. 管理系统里用户角色与权限的设计
  7. 神的战争god无法显示服务器,神的战争GOD
  8. android直播录像,安卓手机怎么录制直播视频
  9. 政府大数据服务,跑马圈地正当时
  10. redis.clients.jedis.exceptions.JedisDataException