How to Use Spring Cloud Gateway’s ProxyExchange for MVC and WebFlux Proxies
This guide demonstrates how to leverage Spring Cloud Gateway's ProxyExchange utility in both Spring MVC and WebFlux applications, showing code examples for proxying requests, extracting path variables, adding headers, handling responses, and configuring sensitive headers.
Environment: SpringBoot 2.5.13.
Spring Cloud Gateway provides a utility object called ProxyExchange that can be used as a method parameter in regular Spring web handlers. It mirrors HTTP verbs for downstream exchanges and, in MVC, also supports forwarding to local handlers via forward() . To use ProxyExchange , include the appropriate module on the classpath: spring-cloud-gateway-mvc (3.1.5) or spring-cloud-gateway-webflux .
MVC Example
<code>@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();
}
}
</code>WebFlux Example
<code>@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();
}
}
</code>The convenience methods on ProxyExchange let handler methods discover and enhance the incoming request URI path. For example, you can extract the tail of a path and forward it downstream:
<code>@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
// If the request is /proxy/path/666, then path = 666
String path = proxy.path("/proxy/path/");
return proxy.uri(home.toString() + "/foos/" + path).get();
}
</code>Target Service Interface
<code>@RestController
@RequestMapping("/business")
public class BusinessController {
@PostMapping("/index")
public Object index(@RequestBody Map<String, Object> body) {
System.out.println("Received payload: " + body);
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("data", "Business processed - " + LocalDateTime.now().getNano());
result.put("message", "success");
return result;
}
}
</code>Gateway Service Interface
<code>@RestController
@RequestMapping("/proxy/api")
public class GatewayController {
@GetMapping("")
public Object order(@RequestHeader("token") String token,
Integer id,
ProxyExchange<Map<String, Object>> exchange) {
System.out.println("token = " + token + ", id = " + id);
Map<String, Object> body = new HashMap<>();
body.put("id", id);
body.put("token", token);
return exchange.uri("http://localhost:9000/business/index").body(body).post();
}
}
</code>You can also add headers to the downstream request using the header() method:
<code>exchange.uri("http://localhost:9000/business/index")
.header("key", "123123")
.body(body)
.post();
</code>To manipulate the response, provide a mapper function to post() (or other HTTP methods). The mapper receives the inbound ResponseEntity and returns a new one:
<code>exchange.uri("http://localhost:9000/business/index")
.header("key", "123123")
.body(body)
.post(result -> {
System.out.println("Response Header: " + result.getHeaders());
return ResponseEntity.ok("success");
});
</code>Sensitive headers such as cookie and authorization , as well as proxy headers (e.g., x-forward-* ), are not forwarded downstream by default. This behavior can be overridden in the configuration:
<code>spring:
cloud:
gateway:
proxy:
sensitive:
- ''
</code>Result screenshots:
Postman request
Console output
End of tutorial.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.