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

Spring UriTemplateHandler.expand未编码加号(+)符号问题及解决咨询

解决RestTemplate UriTemplateHandler处理加号(+)编码问题的方案

针对你遇到的RestTemplate中restTemplate.getUriTemplateHandler().expand()方法对查询参数里的+不编码、传入%2B又双重编码的问题,以下是无需上游修复的几种解决办法:

1. 全局自定义UriTemplateHandler(推荐全局生效)

Spring默认的DefaultUriBuilderFactory遵循application/x-www-form-urlencoded规则,将查询参数中的+视为空格等价物,因此不会编码。我们可以自定义Handler强制将+编码为%2B:

import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;

public class PlusEncodingUriTemplateHandler extends DefaultUriBuilderFactory {
    @Override
    protected UriComponentsBuilder createUriComponentsBuilder(String uriTemplate) {
        return super.createUriComponentsBuilder(uriTemplate)
                .queryParamEncoder((paramName, paramValue) -> {
                    // 先按标准规则编码,再替换+为%2B
                    String encoded = UriUtils.encodeQueryParam(paramValue, StandardCharsets.UTF_8);
                    return encoded.replace("+", "%2B");
                });
    }
}

然后将自定义Handler设置到RestTemplate:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new PlusEncodingUriTemplateHandler());

之后所有通过该RestTemplate发起的请求,查询参数中的+都会被编码为%2B,且不会出现双重编码问题。

2. 单个请求手动控制编码(适合局部特殊场景)

如果只需要针对个别请求处理,可以手动预编码参数并避免双重编码:

import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
import java.net.URI;

// 示例参数
String pathTemplate = "/api/data?key={key}";
String paramValue = "test+value";

// 预编码参数,替换+为%2B
String encodedParam = UriUtils.encodeQueryParam(paramValue, StandardCharsets.UTF_8)
        .replace("+", "%2B");

// 构建URI时确保仅编码一次
URI finalUri = UriComponentsBuilder.fromUriString(pathTemplate)
        .buildAndExpand(encodedParam)
        .encode(StandardCharsets.UTF_8)
        .toUri();

// 发起请求
restTemplate.getForObject(finalUri, YourResponseClass.class);

3. 直接用UriComponentsBuilder构建URI(最灵活)

完全绕过expand()方法,直接构建URI并手动控制编码逻辑:

import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
import java.net.URI;

String paramValue = "a+b+c";
URI uri = UriComponentsBuilder.fromHttpUrl("https://your-domain.com/api/resource")
        // 手动编码参数并替换+
        .queryParam("param", UriUtils.encodeQueryParam(paramValue, StandardCharsets.UTF_8).replace("+", "%2B"))
        .build(true) // true表示使用已编码的参数,不再次编码
        .toUri();

restTemplate.getForObject(uri, String.class);

原理说明

  • 默认规则中,查询参数的+被解析为空格,这是HTTP表单编码的标准行为,但部分服务端会将+视为普通字符,因此需要强制编码。
  • 自定义Handler通过覆盖编码逻辑,将+替换为%2B;手动编码则通过预处理参数,再关闭自动编码避免双重编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:12:57