spring cloud-Gateway:断言-请求头以及请求权重分流等
- 一、断言Header信息要求
- 项目前置环境要求
- 案例一、断言-请求头信息-匹配X-Request-Id
- 1、配置文件及代码
- 2、测试
- 案例二、断言-请求头信息-匹配API版本
- 场景
- 主要配置信息
- 案例三、断言-请求头信息:匹配请求来源
- 场景
- 主要配置信息
- 案例四、断言-请求头信息:匹配用户权限/角色
- 场景
- 主要配置信息
- 二、断言-请求方式
- 案例、请求方式Demo
- 主要配置信息
- 测试
- 三、断言-查询条件
- 案例、断言-查询条件QueryDemo
- 主要配置信息
- 测试
- 四、断言-将请求按设定的权重进行分流
- 涉及到要用权重分流的场景
- 案例、断言-WeightDemo
- 主要配置信息
- 测试
一、断言Header信息要求
需要参数header 和regexp(正则表达式),即key和value,匹配请求携带的信息。实际就是对应请求头携带的信息,官网的案例是X-Request-Id,所以我们第一个案例就以它为例 ;)
项目前置环境要求
- 启动nacos服务,对应版本: 2.2.3 ,jdk1.8或以上。
- 至少1个服务提供者,端口9001,提供一个web接口,【我的是/hello,下文也是以此接口为例】;
- 一个网关服务端口 9966 ;
案例一、断言-请求头信息-匹配X-Request-Id
1、配置文件及代码
网关gateway的yaml配置文件:
server:port: 9966
spring:application:name: gateway-servicecloud:nacos:discovery:server-addr: 192.168.0.103:80gateway:discovery:locator:enabled: false # 关闭注册中心路由功能routes:- id: nacos-provideruri: lb://nacos-provider #路由到注册中心,服务为nacos-provider的服务predicates:- Path=/nancy/** # 路径匹配,则进行路由- Header=X-Request-Id,\d+ #表示数字filters:- StripPrefix=1 # 截取掉断言路径的第一部分
management:endpoint:web:exposure:include: '*'
网关gateway主启动类:
package com.nancy.gateway9966;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication
public class Gateway9966Application {public static void main(String[] args) {SpringApplication.run(Gateway9966Application.class, args);}
}
服务提供者9001,接口
/*** @Auther: gina* @Date: 2025-03-10* @Description:*/
@RestController
@Slf4j
public class UserController {@GetMapping("/hello")public String hello(HttpServletRequest request) {log.info("........Nacos Provider run.......... ");return "9001-----hello Nancy...";}
}
服务提供者yaml
server:port: 9001spring:application:name: nacos-providercloud:discovery:server-addr: 192.168.0.103:80
management:endpoint:web:exposure:include: '*'
服务提供者主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class NacosProvider9001Application {public static void main(String[] args) {SpringApplication.run(NacosProvider9001Application.class, args);}}
服务提供者,引入maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
2、测试
启动9001服务,gateway9966网关侧服务。访问链接:http://localhost:9966/nancy/hello
案例二、断言-请求头信息-匹配API版本
场景
案例一的粒度要粗一些,属于服务之间的隔离;但实际工作中会有粒度更细的场景,比如API 可以同时存在多个版本的场景,举个实际场景的例子:
手机APP,新业务迭代,对于老版本app也要做兼容,但老app界面框架无法更改(涉及到合规和用户体验的考量,一般不会选择强制更新),这时就会有相同业务不同api版本的诉求。
而落地实现的方式之一,可以基于spring cloud 的gateway 的断言来实现,通过断言做API版本隔离,不同版本路由到不同的服务;话不多说直接上实例。
主要配置信息
网关gateway9966的yaml文件关于路由的内容设置:
spring:cloud:gateway:routes:- id: route_api_v1uri: http://nacos-consumer/testV1predicates:- Header=X-API-Version, 1.1.0 # 如果 API 版本为 1.1.0,则路由到 v1 服务- id: route_api_v2uri: http://nacos-consumer/testV2predicates:- Header=X-API-Version, 1.2.0 # 如果 API 版本为 1.2.0,则路由到 v2 服务
测试同案例一,不再赘述。
案例三、断言-请求头信息:匹配请求来源
场景
在处理跨域请求时,会在请求Header中添加Origin字段。使用Header断言可以根据Origin字段的值判断请求的来源,从而设定只限某些来源的请求来访问资源。
主要配置信息
gateway网关侧yaml文件主要配置信息如下:
spring:cloud:gateway:routes:- id: allowed_origin_routeuri: http://backend-servicepredicates:- Header=Origin, https://nancy.com # 只允许来自 https://nancy.com 的请求
案例四、断言-请求头信息:匹配用户权限/角色
场景
微服务架构中,在请求Header里可能会增加用户的角色信息,比如X-User-Role
。基于 此断言的Header信息里用户的角色,将请求路由到不同的资源或服务。
主要配置信息
gateway网关侧yaml文件主要配置信息如下:
spring:cloud:gateway:routes:- id: admin_routeuri: http://nacos-consumer/adminpredicates:- Header=X-User-Role, admin # 用户角色是管理员,则路由到admin服务- id: user_routeuri: http://nacos-consumer/userpredicates:- Header=X-User-Role, user # 用户角色是普通用户,则路由到user服务
二、断言-请求方式
Method:可以设置一个或多个参数,匹配HTTP请求,比如GET、POST
案例、请求方式Demo
主要配置信息
server:port: 9966
spring:application:name: gateway-servicecloud:nacos:discovery:server-addr: 192.168.0.103:80gateway:discovery:locator:enabled: false # 开启注册中心路由功能routes:- id: nacos-provideruri: lb://nacos-provider #路由到注册中心,服务为nacos-provider的服务predicates:- Path=/nancy/** # 路径匹配,则进行路由- Method=POST,GET # 匹配GET请求或者POST请求filters:- StripPrefix=1 # 截取掉断言路径的第一部分
management:endpoint:web:exposure:include: '*'
测试
访问路径:http://localhost:9966/nancy/hello
1、代码中设置的请求方式只有post和get两种,如果访问put方式,会报404,如图:
2、如果请求方式设置为get,则接口是通的,由网关路由到9002端口的hello接口,如下图:
三、断言-查询条件
案例、断言-查询条件QueryDemo
Query:需要指定一个或者多个参数,一个必须参数和一个可选的正则表达式,匹配请求中是否包含第一个参数,
如果有两个参数,则匹配请求中第一个参数的值是否符合正则表达式。
主要配置信息
gateway的配置信息
server:port: 9966
spring:application:name: gateway-servicecloud:nacos:discovery:server-addr: 192.168.0.103:80gateway:discovery:locator:enabled: false # 开启注册中心路由功能routes:- id: nacos-provideruri: lb://nacos-provider #路由到注册中心,服务为nacos-provider的服务predicates:- Path=/nancy/** # 路径匹配,则进行路由- Query=id,.+ # 匹配请求参数,这里如果需要匹配多个参数,可以写多个Queryfilters:- StripPrefix=1 # 截取掉断言路径的第一部分
management:endpoint:web:exposure:include: '*'
测试
测试链接:http://localhost:9966/nancy/hello
当不传id时,测试不通过:
传id以及value值时,测试通过:
四、断言-将请求按设定的权重进行分流
实现路由权重,需要参数 group 和weight(int);按照路由权重选择同一个分组中的路由。
涉及到要用权重分流的场景
案例、断言-WeightDemo
gateway的配置信息
该路由配置 约 80%的流量转发到服务 nacos-consumer ,约20%的流量转发给服务nacos-consumer-openFeign
路由属性Weight接收两个参数:group
和weight(int)
,分流权重按组计算,在断言里配置权重路由配置如下:
主要配置信息
gateway的yaml文件配置如下:
server:port: 9999
spring:application:name: gateway-servicecloud:nacos:discovery:server-addr: 172.18.101.197:80gateway:discovery:locator:enabled: false # 开启注册中心路由功能routes:# 配置流量分流权重- id: nacos-consumer-routeruri: lb://nacos-consumer #路由到注册中心,服务为nacos-consumer的服务predicates:- Path=/testC/** # 路径匹配,则进行路由- Weight=group1, 2filters:- StripPrefix=1 # 截取掉断言路径的第一部分- id: nacos-consumer-openfeignuri: lb://nacos-consumer-openfeign #路由到注册中心,服务为nacos-consumer的服务predicates:- Path=/testC/** # 路径匹配,则进行路由- Weight=group1, 8filters:- StripPrefix=1 # 截取掉断言路径的第一部分management:endpoint:web:exposure:include: '*'
9101和9102接口,分别为:
接口映射明不变,返回值为对应端口
//9102static AtomicInteger a1=new AtomicInteger(0);@GetMapping("/abTest")public String versionB() throws InterruptedException {log.info("端口9102 调用次数 " + a1.incrementAndGet());return "version_B--9102";}//9101private static AtomicInteger a = new AtomicInteger(0);@GetMapping("/abTest")@SentinelResource(value = "version_A")public String versionB() throws InterruptedException {log.info("端口9101 调用次数 " + a.incrementAndGet());return "version_A--9101";}
测试
启动三个服务,注册中心可以看到服务均已注册成功:
测试链接:http://localhost:9999/testC/abTest
验证分流情况,预期结果:9101 约20%的流量,9102约80%的流量。
实际结果:
通过jmeter测试,总请求数量设定1000,从控制台可观测到结果:
可看出请求分流权重,实际结果跟预期相符。