You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过ExchangeFilterFunction修改WebClient请求体并添加自定义键值对

解决WebClient拦截Form请求体并添加自定义键值对的问题

要实现拦截POST请求的Form体并添加自定义键值对,核心难点在于FormInserter是延迟插入的,无法直接获取内部的MultiValueMap。下面是具体的实现方案:

核心思路

  1. 识别目标请求:仅处理POST方法且请求体为BodyInserters.FormInserter的请求;
  2. 提取原Form数据:通过模拟FormInserter的插入操作,将内部键值对导出到临时MultiValueMap;
  3. 修改并替换请求体:检查目标键是否存在,不存在则添加,再用修改后的MultiValueMap重建FormInserter替换原请求体。

代码实现

自定义ExchangeFilterFunction

import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import reactor.core.publisher.Mono;

public class FormEnhanceFilter implements ExchangeFilterFunction {

    private final String targetKey;
    private final String targetValue;

    public FormEnhanceFilter(String targetKey, String targetValue) {
        this.targetKey = targetKey;
        this.targetValue = targetValue;
    }

    @Override
    public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
        // 仅处理POST类型的Form请求
        if (HttpMethod.POST.equals(request.method()) && request.body() instanceof BodyInserters.FormInserter) {
            BodyInserters.FormInserter<String> originalInserter = (BodyInserters.FormInserter<String>) request.body();
            
            // 提取原Form中的所有键值对
            MultiValueMap<String, String> formData = extractFormData(originalInserter);
            
            // 检查并添加自定义键值对
            if (!formData.containsKey(targetKey)) {
                formData.add(targetKey, targetValue);
            }
            
            // 构建新的请求体并替换原请求
            ClientRequest modifiedRequest = ClientRequest.from(request)
                    .body(BodyInserters.fromFormData(formData))
                    .build();
            
            return next.exchange(modifiedRequest);
        }
        // 非目标请求直接放行
        return next.exchange(request);
    }

    private MultiValueMap<String, String> extractFormData(BodyInserters.FormInserter<String> inserter) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        // 调用insert方法将Form数据写入临时Map,这是最可靠的提取方式(避免反射依赖)
        inserter.insert(null, formData, null, null).block();
        return formData;
    }
}

应用过滤器到WebClient

如果是自己创建WebClient:

WebClient webClient = WebClient.builder()
        .filter(new FormEnhanceFilter("custom_key", "your_custom_value"))
        .build();

如果是替换第三方已创建的WebClient:

// thirdPartyWebClient为第三方提供的实例
WebClient modifiedWebClient = thirdPartyWebClient.mutate()
        .filter(new FormEnhanceFilter("custom_key", "your_custom_value"))
        .build();

关键说明

  • 为什么用insert方法提取:FormInserter没有暴露获取内部数据的公开方法,通过模拟插入到临时MultiValueMap是兼容性最好的方案,避免反射带来的版本适配问题;
  • 只针对POST+Form请求:避免拦截其他类型的请求(如JSON体、GET请求),减少不必要的性能开销;
  • 线程安全:LinkedMultiValueMap是线程安全的,且操作都是在请求处理的单线程上下文内执行,不会有并发问题。

内容的提问来源于stack exchange,提问作者Ock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:47:27