Skip to content

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-webmvcspring-cloud-gateway-proxyexchange-webflux)。

以下 MVC 示例将对 /test 的请求代理到远程服务器:

java
@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 的同等示例:

java
@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 路径。例如,您可能想要提取路径的尾部元素并将其传递到下游:

java
@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 并将其转换为传出的响应。

系统对“敏感”头部(默认为 cookieauthorization)以及“跳过”的头部(默认为 content-lengthhost)提供了一流的支持,这些头部不会传递到下游,同时也支持“代理”(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 是不二之选。

Based on Spring Framework.