概述

定义

Spring Cloud Gateway 官网地址 https://spring.io/projects/spring-cloud-gateway/ 最新版本3.1.3

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

Spring Cloud Gateway GitHub源码地址 https://github.com/spring-cloud/spring-cloud-gateway

Spring Cloud Gateway使用了WebFlux技术,而WebFlux技术底层又基于高性能的Reactor模式通信框架Netty。Spring Cloud Gateway基于Spring 5、Spring Boot 2和project Reactor技术上构建异步非阻塞的高吞吐量API网关,提供一种简单且有效的方式来路由到API,并为它们提供横切关注点如安全性、监控/指标和弹性等。Spring Cloud Gateway特性如下:

Spring Cloud Gateway特性如下:

  • 能够在任何请求属性上匹配路由。
  • 谓词和过滤器是特定于路由的。
  • 集成断路器。
  • 集成Spring Cloud DiscoveryClient
  • 编写谓词和过滤器编写易用。
  • 限制请求速率。
  • 路径重写

网关作为系统的唯一流量入口,封装内部系统的架构,所有请求都先经过网关,由网关将请求路由到合适的微服务,优势如下:

  • 简化客户端的工作。网关将微服务封装起来后,客户端只需同网关交互,而不必调用各个不同服务。
  • 降低函数间的耦合度。 一旦服务接口修改,只需修改网关的路由策略,不必修改每个调用该函数的客户端,从而减少了程序间的耦合性。
  • 解放开发人员把精力专注于业务逻辑的实现。由网关统一实现服务路由(灰度与ABTest)、负载均衡、访问控制、流控熔断降级等非业务相关功能,而不需要每个服务 API 实现时都去考虑。
  • 现在前后端分离大趋势下,目前大部分浏览器安全同源策略出现前端请求的跨域问题,网关也是解决跨域问题的一种较完美方式。

流量网关与微服务网关

流量网关(如典型Nginx网关)是指提供全局性的、与后端业务应用无关的策略,例如 HTTPS证书卸载、Web防火墙、全局流量监控等。而微服务网关(如Spring Cloud Gateway)是指与业务紧耦合的、提供单个业务域级别的策略,如服务治理、身份认证等。也就是说,流量网关负责南北向流量调度及安全防护,微服务网关负责东西向流量调度及服务治理。

主流网关

  • Kong 网关:Kong 的性能非常好,非常适合做流量网关,但是对于复杂系统不建议业务网关用 Kong,主要是工程性方面的考虑。基于OpenResty或Nginx+Lua实现。
  • Zuul1.x 网关:Zuul 1.0 的落地经验丰富,但是性能差、基于同步阻塞IO,适合中小架构,不适合并发流量高的场景,因为容易产生线程耗尽,导致请求被拒绝的情况。
  • Gateway 网关:功能强大丰富,性能好,官方基准测试 RPS (每秒请求数)是Zuul的1.6倍,能与 SpringCloud 生态很好兼容,单从流式编程+支持异步上也足以让开发者选择它了。
  • Zuul 2.x:性能与 gateway 差不多,基于非阻塞的,支持长连接,但 SpringCloud 没有集成 zuul2 的计划,并且 Netflix 相关组件都宣布进入维护期,前景未知。

从发展趋势上看,Spring Cloud Gateway作为Spring Cloud生态体系中的网关,目标替代Netflix的Zuul且势在必行。

术语

进一步研究 Spring Cloud Gateway 的配置及其使用之前,我们先了解几个 Spring Cloud Gateway 的核心术语

  • Route(路由):网关的基本组成部分。它由一个ID、一个目标URI、一组谓词和一组过滤器定义。如果聚合谓词或者说断言为真,则匹配路由。
  • Predicate(谓词):这是一个Java 8函数谓词,输入类型是Spring Framework serverwebexchange,匹配HTTP请求中的任何内容,如头或参数。
  • Filter(过滤器):这些是使用特定工厂构建的GatewayFilter实例,可以在发送下游请求之前或之后修改请求和响应。

工作流程

  • 客户端向Spring Cloud Gateway发出请求。
  • 如果网关处理程序映射决定一个请求匹配一个路由,它被发送到网关Web处理程序。
  • 此处理程序通过特定于该请求的过滤器链运行请求。用虚线分隔过滤器的原因是,过滤器可以在发送代理请求之前和之后运行逻辑。
  • 执行所有“预”筛选逻辑。然后发出代理请求。
  • 发出代理请求后,运行“post”过滤器逻辑。

实战

加依赖

项目或模块中加入spring-cloud-starter-gateway

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

如果引入了启动器,但又不希望启用网关,则可以通过设置spring.cloud.gateway.enabled=false来禁用。全部详细配置可以查阅官网,Spring Cloud Gateway详细配置说明 https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/appendix.html

官网提供两种配置谓词和过滤器的方法,分别是shortcuts and fully expanded arguments,译为快捷方式和完全扩展的参数方式,后续例子我们都使用快捷方式,这种方式简洁舒畅,官方的例子也大都是使用快捷方式。

路由配置Route 主要由路由id、目标uri、断言集合和过滤器集合组成

  • id:路由标识,要求唯一,名称任意(默认值 uuid,一般不用,需要自定义)
  • uri:请求最终被转发到的目标地址
  • order: 路由优先级,数字越小,优先级越高
  • predicates:断言数组,即判断条件,如果返回值是boolean,则转发请求到 uri 属性指定的服务中
  • filters:过滤器数组,在请求传递过程中,对请求做一些修改

网关路由初体验

利用前面库存微服务提供的deduct接口,端口为4080,启动库存微服务,访问http://localhost:4080/deduct,显示成功

创建网关微服务模块,pom文件依赖如下,由于后面我们有Gateway整合Nacos和Sentinel的示例,所以这里把其他依赖也先加进来

<?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>simple-ecommerce</artifactId>
<groupId>cn.itxs</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion> <artifactId>ecom-gateway</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>ecom-gateway</name>
<description>a simple electronic commerce platform demo tutorial for gateway service</description> <properties>
<spring-cloud-loadbalancer.version>3.1.3</spring-cloud-loadbalancer.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>${spring-cloud-loadbalancer.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies> </project>

bootstrap.yml配置文件加入建议路由配置如下

server:
port: 4090
spring:
application:
name: ecom-gateway
cloud:
gateway:
routes:
- id: storage_route
uri: http://localhost:4080
predicates:
- Path=/storage-service/**
filters:
- StripPrefix=1

启动网关微服务

访问网关提供api接口http://localhost:4090/storage-service/deduct,匹配storage-service为真后通过过滤器去掉一层也即是storage-service路径去掉,然后转发至uri地址,最终转发url为http://localhost:4080/deduct ,成功返回结果

整合Nacos

本地配置文件bootstrap.yml改为如下,commons-dev.yaml包含服务注册的组

spring:
application:
name: ecom-gateway
profiles:
active: dev
cloud:
nacos:
# 注册中心信息放在配置中心上,每个程序一般只配置配置中心的信息
server-addr: 192.168.50.95:8848
config:
server-addr: ${spring.cloud.nacos.server-addr}
file-extension: yaml
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
group: gateway-group
extension-configs:
- dataId: commons-dev.yaml
group: commons-group
refresh: true
username: itsx
password: itxs123
enabled: true # 默认为true,设置false 来完全关闭 Spring Cloud Nacos Config
refresh-enabled: true # 默认为true,当变更配置时,应用程序中能够获取到最新的值,设置false来关闭动态刷新,我们使用注册中心场景大部分就是动态感知,因此基本使用默认的

将路由配置也一并放在Nacos中配置ecom-gateway-dev.yaml,内容如下,uri这里使用的是库存微服务名称,lb是做负载均衡处理

server:
port: 4090
spring:
cloud:
gateway:
routes:
- id: storage_route
uri: lb://ecom-storage-service
predicates:
- Path=/storage-service/**
filters:
- StripPrefix=1

Nacos中commons-dev.yaml的关于Nacos注册中心使用配置如下,库存微服务也是使用这个,服务注册和发现都在ecom-group组

spring:
cloud:
nacos:
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
group: ecom-group
namespace: a2b1a5b7-d0bc-48e8-ab65-04695e61db01
username: itsx
password: itxs123

启动库存微服务和网关微服务,都注册到同一个组里面

再次访问http://localhost:4090/storage-service/deduct ,正常返回结果,到此我们已经成功整合Nacos

路由断言工厂

Route Predicate Factories为路由断言工厂,官网提供12种路由工厂,如果都没有满足你的需求,还可以自定义路由断言工厂

我们先配置一个未来时间的after断言- After=2022-07-09T23:42:47.789-08:00[Asia/Shanghai]

可以直接访问本机IP,返回一个错误的页面

将after断言改为- Before=2022-07-09T23:42:47.789-08:00[Asia/Shanghai]后则可以正常访问。

  • 其他还有许多规则详细可以查阅官网,如下面,各位可以自己一一尝试

    • Between=2022-07-08T23:42:47.789-08:00[Asia/Shanghai], 2022-07-09T23:42:47.789-08:00[Asia/Shanghai]
    • Cookie=chocolate, ch.p
    • Header=X-Request-Id, \d+
    • Host=**.somehost.org,anotherhost.org
    • Method=GET,POST
    • Query=green
    • RemoteAddr=192.168.1.1/24
    • Weight=group1, 8 Weight=group1, 2
    • XForwardedRemoteAddr=192.168.1.1/24

自定义路由断言工厂

当官方提供的所有断言工厂无法满足业务需求时,还可以自定义断言工厂。添加自定义断言工厂类自定断言工厂主要注意一下几点:

  • 需要声明是Springboot的Bean,添加注解@Component,名称必须以RoutePredicateFactory结尾,这个是命名约束。如果不按照命名约束来命名,那么就会找不到该断言工厂。前缀就是配置中配置的断言。
  • 可以直接复制Gateway中已经实现的断言工厂,修改对应的内容,避免踩坑。
  • 继承父类AbstractRoutePredicateFactory,并重写方法。
  • 需要定义一个Config静态内部类,声明属性来接收 配置文件中对应的断言的信息。
  • 在重写的shortcutFieldOrder方法中,绑定Config中的属性。传入数组的内容需要与Config中的属性一致。
  • 在重写的apply方法中,实现具体验证逻辑, true就是匹配成功 false匹配失败。

新建一个库存数量的路由断言工厂QuantityRoutePredicateFactory.java,如库存在100和200之间可以访问

package cn.itxs.ecom.gateway.factory;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange; import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate; // 自定义路由断言工厂
@Component
public class QuantityRoutePredicateFactory extends AbstractRoutePredicateFactory<QuantityRoutePredicateFactory.Config>{ public QuantityRoutePredicateFactory() {
super(QuantityRoutePredicateFactory.Config.class);
} // 将配置文件中的值按返回集合的顺序,赋值给配置类
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(new String[]{"minQuantity", "maxQuantity"});
} @Override
public Predicate<ServerWebExchange> apply(Consumer<Config> consumer) {
return super.apply(consumer);
} @Override
public Predicate<ServerWebExchange> apply(Config config) {
// 创建网关断言对象
// 检查
return serverWebExchange -> {
// TODO 获取请求参数age,判断是否满足如配置的[100, 200)
MultiValueMap<String, String> queryParams = serverWebExchange.getRequest().getQueryParams();
String quantity = queryParams.getFirst("quantity");
if (StringUtils.hasText(quantity) && quantity.matches("[0-9]+")) {
int iQuantity = Integer.parseInt(quantity);
if (iQuantity >= config.getMinQuantity() && iQuantity < config.getMaxQuantity()) {
return true;
}
}
return false;
};
} // 配置类,属性用于接收配置文件中的值
@Validated
public static class Config {
private int minQuantity;
private int maxQuantity; public int getMinQuantity() {
return minQuantity;
} public void setMinQuantity(int minQuantity) {
this.minQuantity = minQuantity;
} public int getMaxQuantity() {
return maxQuantity;
} public void setMaxQuantity(int maxQuantity) {
this.maxQuantity = maxQuantity;
}
}
}

Nacos网关的配置中增加自定义路由断言工厂配置Quantity

server:
port: 4090
spring:
cloud:
gateway:
routes:
- id: storage_route
uri: lb://ecom-storage-service
predicates:
- Path=/storage-service/**
- Quantity=100,200
filters:
- StripPrefix=1

启动网关微服务,访问http://localhost:4090/storage-service/deduct?quantity=99 ,没有匹配路由策略

而访问http://localhost:4090/storage-service/deduct?quantity=100 ,能够正确返回库存微服务接口结果

**本人博客网站 **IT小神 www.itxiaoshen.com

SpringCloud Gateway微服务网关实战与源码分析-上的更多相关文章

  1. SpringCloudGateway微服务网关实战与源码分析 - 中

    实战 路由过滤器工厂 路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应.路由过滤器的作用域是特定的路由.SpringCloud Gateway包括许多内置的GatewayFilter ...

  2. SpringCloudAlibaba分布式事务解决方案Seata实战与源码分析-上

    概述 定义 Spring Cloud Alibaba Seata 官网地址 https://seata.io/zh-cn/ 最新版本1.5.2 Spring Cloud Alibaba Seata 文 ...

  3. Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战

    Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战 Java生鲜电商平台-  什么是秒杀 通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动 比如说京东秒杀,就是一种定时定量秒杀,在规定 ...

  4. 【一起学源码-微服务】Nexflix Eureka 源码十:服务下线及实例摘除,一个client下线到底多久才会被其他实例感知?

    前言 前情回顾 上一讲我们讲了 client端向server端发送心跳检查,也是默认每30钟发送一次,server端接收后会更新注册表的一个时间戳属性,然后一次心跳(续约)也就完成了. 本讲目录 这一 ...

  5. 【一起学源码-微服务】Nexflix Eureka 源码十三:Eureka源码解读完结撒花篇~!

    前言 想说的话 [一起学源码-微服务-Netflix Eureka]专栏到这里就已经全部结束了. 实话实说,从最开始Eureka Server和Eureka Client初始化的流程还是一脸闷逼,到现 ...

  6. 从flink-example分析flink组件(3)WordCount 流式实战及源码分析

    前面介绍了批量处理的WorkCount是如何执行的 <从flink-example分析flink组件(1)WordCount batch实战及源码分析> <从flink-exampl ...

  7. 微服务网关实战——Spring Cloud Gateway

    导读 作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用.本文对Spring Clou ...

  8. springcloud+gateway微服务整合swagger

    单一的微服务集成swagger: maven: <dependency> <groupId>io.springfox</groupId> <artifactI ...

  9. 【一起学源码-微服务】Nexflix Eureka 源码六:在眼花缭乱的代码中,EurekaClient是如何注册的?

    前言 上一讲已经讲解了EurekaClient的启动流程,到了这里已经有6篇Eureka源码分析的文章了,看了下之前的文章,感觉代码成分太多,会影响阅读,后面会只截取主要的代码,加上注释讲解. 这一讲 ...

随机推荐

  1. 3.1 常用Linux命令

    1.echo命令 echo命令用于在终端设备上输出字符串或变量提取后的值,语法格式为"echo [字符串] [$变量]". 2.date命令 date命令用于显示或设置系统的时间与 ...

  2. 攻防世界-MISC:2017_Dating_in_Singapore

    这是MISC高手进阶区的题目:题目如下: 点击下载附件一,得到一张pdf图片,除此之外就只有题目给的字符串了,不知道是什么意思(查看了一下WP)原来每一串通过"-"隔开的字符串代表 ...

  3. XCTF练习题---CRYPTO---Broadcast

    XCTF练习题---CRYPTO---Broadcast flag:flag{fa0f8335-ae80-448e-a329-6fb69048aae4} 解题步骤: 1.观察题目,下载附件 2.下载完 ...

  4. 记一次burp suite文件上传漏洞实验

    一·文件上传漏洞概念 文件上传漏洞是指 Web 服务器允许用户在没有充分验证文件名称.类型.内容或大小等内容的情况下将文件上传到其文件系统.未能正确执行这些限制可能意味着 即使是基本的图像上传功能也可 ...

  5. 聊聊 HTTPS

    聊聊 HTTPS 本文写于 2021 年 6 月 30 日 最近工作也是越来越忙了,不像上学的时候,一天下来闲着没事可以写两篇博客. 今天来聊一下 HTTPS. HTTP HTTP 是不安全的协议. ...

  6. Centos7上安装python3.7

    Centos7安装python3.7 由于python2和python3在很大程度上有些不同,因为需要,就以决定安装python3.x的版本,但由于Centos上自安装的就是pyhton2.6.所以在 ...

  7. CentOS删除编译安装的Python3

    编译安装Python3 # 下载 # wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz wget http://mirr ...

  8. 143. Reorder List - LeetCode

    Question 143. Reorder List Solution 题目大意:给一个链表,将这个列表分成前后两部分,后半部分反转,再将这两分链表的节点交替连接成一个新的链表 思路 :先将链表分成前 ...

  9. linux篇-linux命令大全

    Linux常用命令大全(非常全!!!) 最近都在和Linux打交道,感觉还不错.我觉得Linux相比windows比较麻烦的就是很多东西都要用命令来控制,当然,这也是很多人喜欢linux的原因,比较短 ...

  10. Spring Boot整合Swagger报错:"this.condition" is null

    前段时间看到群里有吐槽swagger整合问题,当时没仔细看,总以为是姿势不对. 这两天正好自己升级Spring Boot版本,然后突然出现了这样的一个错误: Caused by: java.lang. ...