开发指南须知

本次实践主要在版本:2.2.0.BUILD-SNAPSHOT上进行构建,这个项目提供了构建在Spring生态系统之上API网关。

Spring Cloud Gateway的介绍

Spring Cloud Gateway目标是用一个简单、有效的方式路由到API,并且提供横切的一些关注点,例如:安全、监控、系统性能和弹性等。

API网关介绍

API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  1. 客户端会多次请求不同的微服务,增加了客户端的复杂性。
  2. 存在跨域请求,在一定场景下处理相对复杂。
  3. 认证复杂,每个服务都需要独立认证。
  4. 难以重构,随着项目的迭代,可能需要重新划分微服务。
    • 例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
  5. 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。

以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性。

SpringCloud Gateway技术基础

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

如何引用Spring Cloud Gateway

maven坐标为:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

有关使用当前Spring Cloud构建系统的详细信息,如果你引入了starter,但不想开启gateway,可以设置:

spring.cloud.gateway.enabled=false。

注意

  1. Spring Cloud Gateway 构建在 Spring Boot 2.0, Spring WebFlux, and Project Reactor之上,因此,许多熟悉的同步库(例如:Spring Data 、Spring Security)或模式不适用于Spring Cloud Gateway。

  2. Spring Cloud Gateway需要SpringBoot和SpringWebFlux提供的netty运行时,它不再运行于传统的Servlet容器或一个WAR包。

Route

网关基本构件块,也是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言predicates和一组filters组成。如果聚合断言为真,则匹配路由,说明请求的URL和配置。

Predicate

Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等。

Java 8 Function Predicate. 输入类型是SpringFramework ServerWebExchange. 这允许开发人员匹配来自HTTP请求的任何内容,例如头或参数。

Filter

使用特定工厂构造的 Spring Framework GatewayFilter 实例。在这里,可以在发送downstream 请求之前或之后修改requests和responses。

一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。

理解:
  1. 断言(Predicate):请求匹配;
  2. 过滤器(Filter):对请求或者返回进行过滤增强。

网关提供API全托管服务,丰富的API管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等功能。一般来说网关对外暴露的URL或者接口信息,我们统称为路由信息。

Spring Cloud Gateway的工作原理

GatewayClient请求 Spring Cloud Gateway,如果Gateway Handler Mapping 确定请求与路由匹配,该请求被发送到Gateway Web Handler。此Handler运行时发送请求到具体的请求,其中通过过滤器链。

过滤器链被虚线分隔的原因是过滤器可以在发送代理请求之前或之后执行逻辑。执行所有“预”过滤逻辑,然后发出代理请求。在发出代理请求后,将执行“post”过滤器逻辑。URIs 在路由中没有设置端口,则按照HTTP和HTTPS默认端口设置为80和443。

Spring cloud Gateway发出请求。然后再由Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway web handler。Handler再通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。

Spring Cloud Gateway-路由断言工厂

Spring Cloud Gateway匹配路由作为SpringWebFlux HandlerMapping基础设施的一部分。Spring Cloud Gateway包含许多内置的路由断言工厂,这些断言匹配不同属性的HTTP请求,可以组合多个路由断言工厂,并通过逻辑组合。

Before Route Predicate Factory

Before Route Predicate Factory 有一个时间参数,此断言匹配发生在该时间参数之前的请求。

这个路由匹配发生在 Jan 20, 2017 17:42 Mountain Time (Denver)之前的请求。

After Route Predicate Factory

After Route Predicate Factory有一个时间参数,此断言匹配发生在该时间参数之后的请求。

这个路由匹配发生在 Jan 20, 2017 17:42 Mountain Time (Denver)之后的请求。

Between Route Predicate Factory

Between Route Predicate Factory 有两个时间参数。此断言匹配发生在这两个时间之间的请求。

这个路由匹配发生在 Jan 20, 2017 17:42 Mountain Time (Denver)与Jan 21, 2017 17:42 Mountain Time (Denver)之间的请求。可应用于维护窗口。

Cookie Route Predicate Factory

Cookie Route Predicate Factory 有两个参数,包括cookie名称和正则表达式。此断言匹配cookies包括给定的名称和符合正则表达式的值。

此路由匹配cookie名称为chocolate ,cookie值为ch.p正则表达式,匹配chap,chbp等。

Header Route Predicate Factory

Header Route Predicate Factory 包括两个参数包括头名称和值的正则表达式。此断言匹配一个头信息包括该名称和符合该正则表达式值得请求。

此路由匹配头名称为X-Request-Id且值匹配\d+ 表达式(包含一个或多个数字)。

Host Route Predicate Factory

Host Route Predicate Factory包括一个参数host 名称模式列表。此模式是一种 Ant 风格模式,以 "." 作为分隔符。此断言匹配Host头。另外Host头来源有两种:第一种是请求地址;第二种是自己在http的header头中放入Host变量值。

URI 模板变量也支持这种格式 {sub}.myhost.org。

此路由匹配头文件中的Host值www.somehost.org,beta.somehost.org 或 www.anotherhost.org。此示例均为默认端口80,如果为其他端口,需要在表达式中定义。

此断言提取URI模板变量(如上面示例中定义的子变量)作为名称和值的映射,并将其放置在ServerWebExchange.getAttributes()中,其键在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE属性中定义。

在过滤其中加入如下代码示例:
Map uri_template_variables_attribute=exchange.getAttribute(ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
   // Map variables=ServerWebExchangeUtils.getUriTemplateVariables(exchange);
     uri_template_variables_attribute.forEach((K,V)->{
            System.out.println("K:"+K+"--V:"+V);
      });
  • 访问Host为:www.myhost.org
  • 输出结果:  K:sub--V:www

Filter规律器

Global Filter接口与GatewayFilter具有相同的签名。这些是有条件地应用于所有路由的特殊过滤器。

Combined Global Filter and GatewayFilter Ordering
  • 当请求进入(并匹配路由)时,Filtering Web Handler会将GlobalFilter的所有实例和GatewayFilter的所有路由特定实例添加到过滤器链。

  • 此组合过滤器链通过org.springframework.core.Ordered接口进行排序。可以通过实现getOrder()方法或者使用@Order注解。

Spring Cloud Gateway区分了过滤器逻辑执行的“请求”和“响应”阶段,具有最高优先级的过滤器将是“请求”阶段的第一个和“响应”阶段的最后一个 。

ANT通配符有三种:

而上面多数的匹配规则运算符号都是有AntPathMatcher对象进行实现的

private AntPathMatcher antPathMatcher = new AntPathMatcher();
  • ?:匹配任意一个单个字符
    • :匹配0或者任意数量的字符
  • ** :匹配0和或者更多目录的字符
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered { private AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
//商城api接口,校验用户必须登录
if(antPathMatcher.match("/api/**/auth/**", path)) {
List<String> tokenList = request.getHeaders().get("token");
if(null == tokenList) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
} else {
// Boolean isCheck = JwtUtils.checkToken(tokenList.get(0));
// if(!isCheck) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
// }
}
}
//内部服务接口,不允许外部访问
if(antPathMatcher.match("/**/inner/**", path)) {
ServerHttpResponse response = exchange.getResponse();
return out(response);
}
return chain.filter(exchange);
} @Override
public int getOrder() {
return 0;
} private Mono<Void> out(ServerHttpResponse response) {
JsonObject message = new JsonObject();
message.addProperty("success", false);
message.addProperty("code", 28004);
message.addProperty("data", "鉴权失败");
byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
//response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
}

自定义异常处理

服务网关调用服务时可能会有一些异常或服务不可用,它返回错误信息不友好,需要我们覆盖处理。

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

参考资料

【SpringCloud技术专题】「Gateway网关系列」(3)微服务网关服务的Gateway全流程开发实践指南(2.2.X)的更多相关文章

  1. 【分布式技术专题】「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

    Minio的元数据 数据存储 MinIO对象存储系统没有元数据数据库,所有的操作都是对象级别的粒度的,这种做法的优势是: 个别对象的失效,不会溢出为更大级别的系统失效. 便于实现"强一致性& ...

  2. 深入Java微服务之网关系列1:什么是网关

    ​ 前言 近来,在想着重构一个新的产品.准备采用微服务的技术解决方案,来搭建基础设施框架.网关,是一个必不可少的组件.那么,网关到底是什么? 其又有什么特点或者特性,成为微服务必不可少的组件呢?今天, ...

  3. 【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)

    前提介绍 Feign是SpringCloud中服务消费端的调用框架,通常与ribbon,hystrix等组合使用. 由于遗留原因,某些项目中,整个系统并不是SpringCloud项目,甚至不是Spri ...

  4. 【SpringCloud技术专题】「Eureka源码分析」从源码层面让你认识Eureka工作流程和运作机制(上)

    前言介绍 了解到了SpringCloud,大家都应该知道注册中心,而对于我们从过去到现在,SpringCloud中用的最多的注册中心就是Eureka了,所以深入Eureka的原理和源码,接下来我们要进 ...

  5. 【Java技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路

    序列化和反序列化 序列化就是指把对象转换为字节码: 对象传递和保存时,保证对象的完整性和可传递性.把对象转换为有字节码,以便在网络上传输或保存在本地文件中: 反序列化就是指把字节码恢复为对象: 根据字 ...

  6. 【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析

    零拷贝Zero-Copy 我们先来看下它的定义: "Zero-copy" describes computer operations in which the CPU does n ...

  7. 🏆(不要错过!)【CI/CD技术专题】「Jenkins实战系列」(3)Jenkinsfile+DockerFile实现自动部署

    每日一句 没有人会因学问而成为智者.学问或许能由勤奋得来,而机智与智慧却有懒于天赋. 前提概要 Jenkins下用DockerFile自动部署Java项目,项目的部署放心推向容器化时代机制. 本节需要 ...

  8. 🏆【CI/CD技术专题】「Docker实战系列」(1)本地进行生成镜像以及标签Tag推送到DockerHub

    背景介绍 Docker镜像构建成功后,只要有docker环境就可以使用,但必须将镜像推送到Docker Hub上去.创建的镜像最好要符合Docker Hub的tag要求,因为在Docker Hub注册 ...

  9. ☕【难点攻克技术系列】「海量数据计算系列」如何使用BitMap在海量数据中对相应的进行去重、查找和排序

    BitMap(位图)的介绍 BitMap从字面的意思,很多人认为是位图,其实准确的来说,翻译成基于位的映射,其中数据库中有一种索引就叫做位图索引. 在具有性能优化的数据结构中,大家使用最多的就是has ...

随机推荐

  1. 『学了就忘』Linux系统管理 — 84、Linux中进程的管理

    目录 1.Linux系统中的信号 2.杀掉进程的命令 (1)kill命令 (2)killall命令 (3)pkill命令 1.Linux系统中的信号 Linux系统中可以识别的信号较多,我们可以使用命 ...

  2. 从 CPython 源码角度看 Python 垃圾回收机制

    环状双向链表 refchain 在 Python 程序中创建的任何对象都会被放到 refchain 链表中,当创建一个 Python 对象时,内部实际上创建了一些基本的数据: 上一个对象 下一个对象 ...

  3. 【分布式技术专题】「OSS中间件系列」Minio的文件服务的存储模型及整合Java客户端访问的实战指南

    Minio的元数据 数据存储 MinIO对象存储系统没有元数据数据库,所有的操作都是对象级别的粒度的,这种做法的优势是: 个别对象的失效,不会溢出为更大级别的系统失效. 便于实现"强一致性& ...

  4. [BUUCTF]REVERSE——crackMe

    crackMe 附件 步骤: 例行检查,32位程序,无壳 32位ida载入,已知用户名welcomebeijing,解密码,直接看main函数 可以看到程序是个死循环,只有满足sub_404830函数 ...

  5. IO复用的三种方法(select,poll,epoll)深入理解

    (一)IO复用是Linux中的IO模型之一,IO复用就是进程告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程处理,从而不会在单个IO上阻塞了,Linux中,提供 ...

  6. ACwing1212. 地宫取宝

    题目: X 国王有一个地宫宝库,是 n×m 个格子的矩阵,每个格子放一件宝贝,每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走过某个 ...

  7. JAVA接收postman的中raw的参数

    /** * java获取raw */ public static String readRaw(InputStream inputStream) { String result = "&qu ...

  8. ORACLE数据库登录显示ORA-28001: the password has expired

    Oracle数据库登录显示 "这个密码已过期,请输入新密码" 点击win键 找到Oracle的SQL Plus 点击打开之后输入登录的用户名密码,然后会显示该密码已过期,输入新口令 ...

  9. windows串口之虚拟串口和Access port

    关于 本文将介绍自己常用的串口工具,演示环境为Windows. 1. 虚拟串口 1.1 没有那么多的物理串口, 用虚拟串口来凑.需要软件Configure Virtual Serial Port Dr ...

  10. 【LeetCode】647. Palindromic Substrings 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:暴力循环 方法二:固定起点向后找 方法三:动 ...