WebClient URI模板变量被bodyValue中POJO字段覆盖是否为预期行为?
Hey, this is actually expected behavior from Spring WebClient! Let me break down what's happening here, where to find the relevant code/docs, and how to work around it if you don't want this behavior.
Why This Happens
Spring WebClient is designed to pull URI template variables from multiple sources when resolving placeholders in your base URL. The sources it checks (in order of priority, later sources override earlier ones) are:
- Variables explicitly passed to the
uri()method - Bean properties from the request body object (when using
bodyValue()) - Default URI variables set when building the WebClient
In your case, the service and namespace fields in your ExampleRequest are being picked up as URI variables and overriding the default values you set during WebClient initialization. This is intended to simplify common use cases where you want to reuse request body data in URIs (like /users/{userId} where userId exists in the request body) without manually passing variables twice.
Source Code & Documentation
Source Code
The core logic lives in org.springframework.web.util.DefaultUriBuilderFactory, specifically the expandUri method. This method creates a CompositeUriTemplateVariables instance that combines multiple variable sources:
- Your default variables are wrapped in a
MapUriTemplateVariables - The request body's properties are wrapped in a
BeanPropertyUriTemplateVariables, which uses reflection to read getter methods for field values
When resolving placeholders, CompositeUriTemplateVariables checks sources in reverse order of addition—since the body's variables are added after the defaults, they take precedence and overwrite the default values.
Documentation
Spring's official WebClient docs explicitly note that request body bean properties are used as a source for URI template variables when using bodyValue(). This is part of the URI resolution feature set to streamline request construction.
How to Prevent This
If you don't want the request body fields to interfere with your URI variables, you have a straightforward options:
- Build the URI explicitly in the
uri()method, avoiding base URL placeholders altogether:webClient.post() .uri(uriBuilder -> uriBuilder .scheme("http") .host("foo.bar.svc.cluster.local") .path("/baz") .build()) .bodyValue(yourExampleRequest) .retrieve(); - Explicitly pass variables in the
uri()method to override any body-derived values:webClient.post() .uri("/baz", Map.of("service", "foo", "namespace", "bar")) .bodyValue(yourExampleRequest) .retrieve();
内容的提问来源于stack exchange,提问作者olan

