Spring Cloud Gateway 内置 Filter 实战:AddRequestHeader 与 RewritePath
Spring Cloud Gateway 内置 Filter 实战指南。重点讲解 AddRequestHeader 和 RewritePath 的配置方式与正则匹配逻辑。通过 YAML 和 Java 代码示例演示请求头添加与路径重写功能。涵盖 Filter 执行顺序、高级应用场景及性能优化建议。帮助开发者构建灵活的路由网关服务。

Spring Cloud Gateway 内置 Filter 实战指南。重点讲解 AddRequestHeader 和 RewritePath 的配置方式与正则匹配逻辑。通过 YAML 和 Java 代码示例演示请求头添加与路径重写功能。涵盖 Filter 执行顺序、高级应用场景及性能优化建议。帮助开发者构建灵活的路由网关服务。

在现代微服务架构中,API 网关扮演着至关重要的角色。它作为系统的统一入口,负责请求路由、负载均衡、安全控制、限流熔断、协议转换等多种功能。Spring Cloud Gateway 作为 Spring 官方推荐的 API 网关实现,提供了强大的路由和过滤机制。其中,内置 Filter 是其核心特性之一,允许我们在请求到达目标服务之前或之后执行特定的操作。
本文将深入探讨 Spring Cloud Gateway 中常用的 内置 Filter,特别是 AddRequestHeader 和 RewritePath,并结合实际 Java 代码示例进行演示。我们将从基础概念出发,逐步引导你掌握这些 Filter 的使用方法,并通过图表和代码片段来加深理解。
Spring Cloud Gateway 是 Spring 官方推出的下一代 API 网关,基于 Spring Framework 5、Project Reactor 和 Spring Boot 2 构建。它旨在提供一种简单而有效的方式来路由到任何后端服务,并且能够轻松地添加横切关注点(如安全性、监控、响应压缩等)。
与传统的 Zuul 相比,Gateway 提供了更强大的路由匹配能力、更好的性能以及更丰富的过滤器机制。它基于 Netty 异步非阻塞 I/O 模型,能够处理高并发请求。
Spring Cloud Gateway 的核心组件包括:
Spring Cloud Gateway 提供了多种类型的 Filter:
AddRequestHeader, RewritePath, SetStatus 等。AddRequestHeader 是一个非常实用的内置 Filter,它的主要作用是在请求发送到下游服务之前,向请求头(Headers)中添加一个或多个自定义的键值对。这对于传递服务间调用所需的信息(如认证令牌、追踪 ID 等)非常有用。
可以通过 YAML 或 Java 配置方式来使用 AddRequestHeader。
spring:
cloud:
gateway:
routes:
- id: add-header-route
uri: lb://service-a
predicates:
- Path=/api/service-a/**
filters:
- name: AddRequestHeader
args:
name: X-Forwarded-For
value: 192.168.1.1
- name: AddRequestHeader
args:
name: X-Custom-Header
value: MyValue
这个配置表示,当请求路径以 /api/service-a/ 开头时,网关会自动在请求头中添加两个字段:
X-Forwarded-For: 192.168.1.1X-Custom-Header: MyValueimport org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("add-header-route", r -> r.path("/api/service-a/**")
.filters(f -> f.addRequestHeader("X-Forwarded-For", "192.168.1.1")
.addRequestHeader("X-Custom-Header", "MyValue"))
.uri("lb://service-a"))
.build();
}
}
假设我们有一个用户服务 user-service,它需要知道请求来自哪个客户端,以便进行日志记录和安全审计。我们可以利用 AddRequestHeader 来实现。
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: AddRequestHeader
args:
name: X-Client-ID
value: ${client.id:default-client}
- name: AddRequestHeader
args:
name: X-Request-Timestamp
value: ${timestamp:${now}}
或者在 Java 配置中:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service-route", r -> r.path("/api/users/**")
.filters(f -> f.addRequestHeader("X-Client-ID", "${client.id:default-client}")
.addRequestHeader("X-Request-Timestamp", String.valueOf(System.currentTimeMillis())))
.uri("lb://user-service"))
.build();
}
name 和 value 参数都是必需的。value 支持占位符和 SpEL 表达式,这使得动态设置值成为可能。RewritePath Filter 允许你在请求到达下游服务之前,修改请求的路径(Path)。这是非常有用的,尤其是在需要将网关暴露的 API 路径与后端服务的内部路径不一致时。例如,网关可能希望将 /api/v1/users 映射到后端服务的 /users 路径。
spring:
cloud:
gateway:
routes:
- id: rewrite-path-route
uri: lb://backend-service
predicates:
- Path=/api/v1/**
filters:
- name: RewritePath
args:
regexp: /api/v1/(?<segment>.*)
replacement: /${segment}
这个配置的意思是:当请求路径是 /api/v1/... 时,将路径重写为 /...。例如,请求 /api/v1/users/123 会被重写为 /users/123 并转发到 backend-service。
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite-path-route", r -> r.path("/api/v1/**")
.filters(f -> f.rewritePath("/api/v1/(?<segment>.*)", "/${segment}"))
.uri("lb://backend-service"))
.build();
}
}
考虑一个场景,我们的前端应用通过网关访问后端服务。前端可能期望 API 路径是 /api/v2/products,但后端服务的接口设计是 /products。这时,我们就可以使用 RewritePath 来实现映射。
spring:
cloud:
gateway:
routes:
- id: product-service-route
uri: lb://product-service
predicates:
- Path=/api/v2/products/**
filters:
- name: RewritePath
args:
regexp: /api/v2/products/(?<rest>.*)
replacement: /products/${rest}
这个配置会将请求 /api/v2/products/123 重写为 /products/123。
RewritePath 的关键在于 regexp 和 replacement 参数。它们使用 Java 的正则表达式语法。
regexp: 定义一个正则表达式来匹配原始路径。replacement: 定义如何根据捕获组替换原始路径。${xxx} 是引用捕获组的方式。原始路径:/api/v1/users/123
正则:/api/v1/(?<segment>.*)
替换:/${segment}
结果:/users/123
原始路径:/api/v1/users/123/orders/456
正则:/api/v1/(?<resource>.*)/(?<id>.*)/(?<subResource>.*)/(?<subId>.*)
替换:/${resource}/${id}/${subResource}/${subId}
结果:/users/123/orders/456
原始路径:/api/v1/users?limit=10&offset=20
正则:/api/v1/(?<path>.*)
替换:/${path}
结果:/users?limit=10&offset=20 (注意:查询参数通常不会被 RewritePath 修改,除非特别处理)
regexp 必须是一个有效的 Java 正则表达式。replacement 中的 ${groupName} 用于引用正则表达式中的命名捕获组。RewritePath 只改变请求的路径部分,不影响查询参数(Query Parameters)和请求方法。除了上述两个核心 Filter,Spring Cloud Gateway 还提供了许多其他内置 Filter,这里简要介绍一些常用的:
用于设置 HTTP 响应的状态码。
spring:
cloud:
gateway:
routes:
- id: set-status-route
uri: lb://some-service
predicates:
- Path=/status-test/**
filters:
- name: SetStatus
args:
status: 404
与 AddRequestHeader 类似,但它是在响应返回给客户端之前添加响应头。
spring:
cloud:
gateway:
routes:
- id: add-response-header-route
uri: lb://some-service
predicates:
- Path=/response-header-test/**
filters:
- name: AddResponseHeader
args:
name: X-Response-Header
value: ResponseValue
移除请求路径开头的指定数量的路径段。
spring:
cloud:
gateway:
routes:
- id: strip-prefix-route
uri: lb://some-service
predicates:
- Path=/api/v1/**
filters:
- name: StripPrefix
args:
parts: 2
例如,请求 /api/v1/users/123 会被处理为 /users/123。
在请求路径前添加一个前缀。
spring:
cloud:
gateway:
routes:
- id: prefix-path-route
uri: lb://some-service
predicates:
- Path=/users/**
filters:
- name: PrefixPath
args:
prefix: /api/v1
例如,请求 /users/123 会被处理为 /api/v1/users/123。
为了更好地理解这些 Filter 的应用,我们将创建一个简单的 Spring Cloud Gateway 项目,并演示如何使用 AddRequestHeader 和 RewritePath。
首先,我们需要一个 Spring Boot 项目。你可以使用 Spring Initializr 来初始化项目。
选择以下依赖项:
src/
└── main/
├── java/
│ └── com/
│ └── example/
│ └── gatewaydemo/
│ ├── GatewayDemoApplication.java
│ └── config/
│ └── GatewayConfig.java
└── resources/
└── application.yml
创建 application.yml 文件:
server:
port: 8080
spring:
application:
name: gateway-demo
cloud:
gateway:
routes:
# 示例 1: 使用 AddRequestHeader
- id: header-test-route
uri: https://httpbin.org
predicates:
- Path=/api/header-test/**
filters:
- name: AddRequestHeader
args:
name: X-Gateway-Source
value: gateway-demo
- name: AddRequestHeader
args:
name: X-Test-Value
value: test-value-123
# 示例 2: 使用 RewritePath
- id: rewrite-test-route
uri: https://httpbin.org
predicates:
- Path=/api/rewrite-test/**
filters:
- name: RewritePath
args:
regexp: /api/rewrite-test/(?<rest>.*)
replacement: /${rest}
# 示例 3: 结合使用
- id: combined-test-route
uri: https://httpbin.org
predicates:
- Path=/api/combined/**
filters:
- name: AddRequestHeader
args:
name: X-Combined-Header
value: combined-value
- name: RewritePath
args:
regexp: /api/combined/(?<rest>.*)
replacement: /${rest}
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
package com.example.gatewaydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayDemoApplication.class, args);
}
}
虽然我们使用了 YAML 配置,但也可以通过 Java 配置类来实现。创建 config/GatewayConfig.java:
package com.example.gatewaydemo.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 通过 Java 配置添加一个路由
.route("java-configured-route", r -> r.path("/api/java-test/**")
.filters(f -> f.addRequestHeader("X-Java-Config", "true")
.rewritePath("/api/java-test/(?<rest>.*)", "/${rest}"))
.uri("https://httpbin.org"))
.build();
}
}
运行 GatewayDemoApplication 主类,确保项目成功启动。
启动后,可以通过浏览器或 curl 工具来测试。
访问:http://localhost:8080/api/header-test/get
这个请求会被转发到 https://httpbin.org/get,并且会自动添加我们指定的请求头。
你可以通过访问 https://httpbin.org/headers 来查看请求头信息:
curl -X GET http://localhost:8080/api/header-test/get
访问:http://localhost:8080/api/rewrite-test/post
这个请求路径会被重写,然后转发到 https://httpbin.org/post。
curl -X POST http://localhost:8080/api/rewrite-test/post
访问:http://localhost:8080/api/combined/get
这个请求会同时添加请求头并重写路径。
curl -X GET http://localhost:8080/api/combined/get
Spring Cloud Gateway 中的 Filter 执行顺序非常重要,因为它决定了请求和响应如何被处理。
Filter 分为两种类型:
Filter 的执行顺序遵循以下规则:
你可以通过 org.springframework.core.Ordered 接口来控制 Filter 的执行顺序。数字越小优先级越高。
请求进入 -> 全局前置过滤器 -> 路由匹配 -> 路由过滤器 -> 目标服务 -> 响应返回 -> 全局后置过滤器 -> 响应返回给客户端
如果你需要自定义某个 Filter 的顺序,可以实现 Ordered 接口:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class CustomGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("Custom filter executed before routing");
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
System.out.println("Custom filter executed after routing");
}));
}
@Override
public int getOrder() {
return 1;
}
}
AddRequestHeader 的 value 参数支持 SpEL 表达式,这使得动态设置 Header 成为可能。
spring:
cloud:
gateway:
routes:
- id: dynamic-header-route
uri: lb://service-a
predicates:
- Path=/api/dynamic/**
filters:
- name: AddRequestHeader
args:
name: X-Timestamp
value: #{T(java.time.Instant).now().toEpochMilli()}
- name: AddRequestHeader
args:
name: X-User-Agent
value: #{request.headers['User-Agent']}
对于复杂的路径重写需求,可以结合多个 RewritePath 或使用更高级的路由逻辑。
spring:
cloud:
gateway:
routes:
- id: complex-rewrite-route
uri: lb://service-a
predicates:
- Path=/api/v3/users/*/orders/*
filters:
- name: RewritePath
args:
regexp: /api/v3/users/(?<userId>.*)/orders/(?<orderId>.*)
replacement: /users/${userId}/orders/${orderId}
可以结合 AddRequestHeader 来传递认证信息。
spring:
cloud:
gateway:
routes:
- id: auth-integration-route
uri: lb://protected-service
predicates:
- Path=/api/secure/**
filters:
- name: AddRequestHeader
args:
name: Authorization
value: Bearer ${auth.token}
不是所有的 Filter 都是免费的。过多的 Filter 会增加请求处理时间。应该根据实际需求选择性地使用 Filter。
RewritePath 虽然强大,但过度使用可能导致路径混乱,增加维护难度。尽量保持路径映射清晰简洁。
对于频繁访问的路由,可以考虑使用缓存机制或提前预热网关实例,以提高响应速度。
为关键的 Filter 添加监控和日志记录,便于问题排查和性能分析。
Spring Cloud Gateway 的内置 Filter 是实现灵活路由和增强功能的强大工具。通过本文的介绍和实战演练,我们深入了解了 AddRequestHeader 和 RewritePath 的工作原理和使用方法。它们不仅简化了开发流程,还增强了系统的灵活性和可扩展性。
掌握这些 Filter 的使用,意味着你可以更有效地构建和管理微服务架构中的 API 网关。无论是简单的请求头注入还是复杂的路径重写,都能通过这些内置工具轻松实现。记住,合理的设计和配置是保证网关高效运行的关键。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online