Spring Web MVC 或 WebFlux 中的 Proxy Exchange
警告
以下内容描述了一种替代风格的网关。下文中提到的内容均不适用于 Spring Cloud Gateway Server。
1. 如何引入 Spring Cloud Gateway Proxy Exchange
要在项目中引入 Spring Cloud Gateway Proxy Exchange:
- 对于 MVC 版本:使用 Group ID 为
org.springframework.cloud且 Artifact ID 为spring-cloud-gateway-proxyexchange-webmvc的依赖。 - 对于 WebFlux 版本:使用 Group ID 为
org.springframework.cloud且 Artifact ID 为spring-cloud-gateway-proxyexchange-webflux的依赖。
有关如何使用当前的 Spring Cloud 版本列设置构建系统的详细信息,请参阅 Spring Cloud 项目页面。
2. 使用 Proxy Exchange
Spring Cloud Gateway 提供了一个名为 ProxyExchange 的工具对象。您可以在常规的 Spring Web 处理器(Handler)中将其作为方法参数使用。它通过镜像 HTTP 动词的方法支持基础的下游 HTTP 交换。
在 MVC 中,它还支持通过 forward() 方法转发到本地处理器。
要使用 ProxyExchange,请在您的类路径中包含正确的模块(spring-cloud-gateway-proxyexchange-webmvc 或 spring-cloud-gateway-proxyexchange-webflux)。
以下 MVC 示例将对 /test 的请求代理到远程服务器:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}以下是 WebFlux 的同等示例:
@RestController
@SpringBootApplication
public class GatewaySampleApplication {
@Value("${remote.home}")
private URI home;
@GetMapping("/test")
public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
return proxy.uri(home.toString() + "/image/png").get();
}
}ProxyExchange 上的便捷方法使处理器方法能够发现并增强传入请求的 URI 路径。例如,您可能想要提取路径的尾部元素并将其传递到下游:
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
String path = proxy.path("/proxy/path/");
return proxy.uri(home.toString() + "/foos/" + path).get();
}Spring MVC 和 WebFlux 的所有特性都可用于网关处理器方法。因此,您可以注入请求头和查询参数,并可以使用映射注解中的声明来约束传入请求。有关这些特性的更多详细信息,请参阅 Spring MVC 的 @RequestMapping 文档。
您可以使用 ProxyExchange 上的 header() 方法向下游响应添加头部。
您还可以通过向 get() 方法(以及其他方法)添加映射器(Mapper)来操纵响应头(以及响应中您喜欢的任何其他内容)。映射器是一个 Function,它接收传入的 ResponseEntity 并将其转换为传出的响应。
系统对“敏感”头部(默认为 cookie 和 authorization)以及“跳过”的头部(默认为 content-length 和 host)提供了一流的支持,这些头部不会传递到下游,同时也支持“代理”(x-forwarded-*)头部。“跳过”头部的理念是,将它们拷贝到下游请求时可能会产生问题。例如:由于 ProxyExchange 调用下游端点的方式,内容的长度可能已经改变,甚至可能使用了 Transfer-Encoding: chunked 代替了 Content-Length 头部。
补充教学 —— 什么时候用 ProxyExchange?
通常我们提到的“Spring Cloud Gateway”是一个独立的、基于断言和过滤器配置的网关服务。而 ProxyExchange 提供了一种完全不同的“手动编程”模式。
1. 核心差异:
- 标准网关:配置驱动。你写 YAML,网关根据规则自动帮你转发。逻辑发生在网关框架内部。
- ProxyExchange:代码驱动。你写 Controller 并在代码里显式调用
proxy.get()。逻辑发生在你自己的业务代码里。
2. 适用场景:
- 在现有业务应用中“顺便”做代理:你有一个现有的微服务,想把其中某几个特定的接口无缝转发给另一个老系统,但又不想为了这几个接口专门部署一套网关集群。
- 极其复杂的动态路由:如果你的路由规则不是简单的“路径匹配”,而是需要查询数据库、甚至调用 AI 模型来决定转发到哪个 URL,在 Java Controller 里写这些逻辑显然比写自定义 Predicate 更直观。
- BFF (Backend For Frontend) 层:在 BFF 层中,你可能需要合并多个接口的数据,或者将部分接口原样转发,
ProxyExchange非常适合这种混搭模式。
3. 局限性:
- 它不具备标准网关那种丰富的过滤器生态(如熔断、限流等自动配置)。如果需要这些功能,你需要手动在 Controller 里集成 Hystrix 或 Sentinel。
总结:如果你需要的是一个专门的流量入口,请使用 Spring Cloud Gateway Server;如果你只是想在自己的代码里方便地做一次“请求搬运”,ProxyExchange 是不二之选。