如何通过Spring WebFlux Integration为出站网关添加请求属性
出站网关XML配置如下:
<outbound-gateway id="reactiveFullConfig" url="http://localhost:8080/hello" http-method="GET" request-channel="requests" reply-timeout="1234" extract-request-payload="false" expected-response-type="java.lang.String" mapped-request-headers="requestHeader1, requestHeader2" mapped-response-headers="responseHeader" reply-channel="replies" charset="UTF-8" order="77" auto-startup="false" transfer-cookies="true" reply-payload-to-flux="true" body-extractor="bodyExtractor" publisher-element-type-expression="headers.elementType" extract-response-body="false"> <uri-variable name="foo" expression="headers.bar"/> </outbound-gateway>
需求:在请求发送到request通道前,为每个请求设置动态可变的request属性,效果等价于WebClient中通过.attribute()方法设置请求属性:
webClient.get().uri("http://localhost:8080/hello") .attribute("MYCUSTOMATTRIBUTE_1", "customvalue") .retrieve() .toEntity(String.class) .block() .getBody();
当前发送请求的代码:
DirectChannel requestChannel = context.getBean("requestChannel", DirectChannel.class); requestChannel.send(MessageBuilder.withPayload("Test message").build());
Spring WebFlux Integration是否提供类似WebClient .attribute()的实现方式?
另外,尝试通过消息头传递值,但ClientRequest中无法获取自定义头requestHeader1(已在mapped-request-headers中配置该头):
requestChannel.send(MessageBuilder.withPayload("Test message").setHeader("requestHeader1","customvalue").build());
1. 利用request-configurer定制ClientRequest属性
Spring WebFlux Integration的WebClientOutboundGateway(对应XML中的<outbound-gateway>)支持通过ClientRequest.Builder定制请求,包括设置请求属性。核心是通过网关的request-configurer注入请求定制逻辑,从消息头中提取动态值并设置到ClientRequest。
方式一:XML配置直接内嵌SpEL定制逻辑
修改出站网关配置,添加request-configurer,通过SpEL从消息头读取属性值并设置到ClientRequest:
<outbound-gateway id="reactiveFullConfig" url="http://localhost:8080/hello" http-method="GET" request-channel="requests" reply-timeout="1234" extract-request-payload="false" expected-response-type="java.lang.String" mapped-request-headers="requestHeader1, requestHeader2" mapped-response-headers="responseHeader" reply-channel="replies" charset="UTF-8" order="77" auto-startup="false" transfer-cookies="true" reply-payload-to-flux="true" body-extractor="bodyExtractor" publisher-element-type-expression="headers.elementType" extract-response-body="false"> <uri-variable name="foo" expression="headers.bar"/> <request-configurer> <bean class="org.springframework.integration.webflux.support.WebClientRequestConfigurer"> <property name="requestCustomizer"> <value> builder -> builder.attribute('MYCUSTOMATTRIBUTE_1', headers['MYCUSTOMATTRIBUTE_1']) </value> </property> </bean> </request-configurer> </outbound-gateway>
发送消息时在头中传入动态属性值:
DirectChannel requestChannel = context.getBean("requestChannel", DirectChannel.class); requestChannel.send(MessageBuilder.withPayload("Test message") .setHeader("MYCUSTOMATTRIBUTE_1", "customvalue") .build());
方式二:自定义ClientRequestCustomizer实现复杂逻辑
如果需要更复杂的属性处理逻辑,比如从上下文中获取值,可以定义自定义的Function<ClientRequest.Builder, ClientRequest.Builder> Bean:
@Component("customAttributeRequestCustomizer") public class CustomAttributeRequestCustomizer implements Function<ClientRequest.Builder, ClientRequest.Builder> { @Override public ClientRequest.Builder apply(ClientRequest.Builder builder) { // 获取当前处理的消息 Message<?> currentMessage = IntegrationMessageHeaderAccessor.getCurrentMessage(); if (currentMessage != null) { // 从消息头提取动态属性值 String customValue = (String) currentMessage.getHeaders().get("MYCUSTOMATTRIBUTE_1"); builder.attribute("MYCUSTOMATTRIBUTE_1", customValue); } return builder; } }
然后在XML网关配置中引用该Bean:
<outbound-gateway id="reactiveFullConfig" ... request-configurer="customAttributeRequestCustomizer"> ... </outbound-gateway>
2. 解决自定义头无法获取的问题
你之前尝试通过消息头传递requestHeader1但在ClientRequest中拿不到,原因在于:
mapped-request-headers的作用是将消息头映射为HTTP请求头,而非ClientRequest的属性。如果要获取HTTP头,可以通过ClientRequest.headers()访问;如果要设置ClientRequest的属性,必须使用上述request-configurer方式。- 注意消息头名称的大小写:消息头是区分大小写的,确保设置和读取的头名称完全一致。
总结
Spring WebFlux Integration完全支持类似WebClient .attribute()的动态属性设置能力,通过request-configurer结合消息头传递动态值,即可为每个请求设置不同的ClientRequest属性。
内容的提问来源于stack exchange,提问作者ProblemSolver

