使用Spring RestTemplate正确转义URL变量(含加号转义)
我太懂这个痛点了!当用RestTemplate.exchange发送带参数的GET请求时,参数里的加号(+)总是被Spring当成空格解析,试过UriComponentsBuilder和UriTemplate都只能搞定空格,加号死活不转义对吧?这其实是Spring默认的URI编码规则在搞鬼。
为啥会这样?
Spring默认遵循RFC 3986规范处理URI编码,在Query参数里,加号(+)被定义成了空格的等价表示。所以默认的expand()和encode()方法根本不会把参数里的加号转成%2B——它觉得这是合法的空格替代符,不是你要传递的实际字符。
靠谱的解决方案
这里有两种方法能彻底解决这个问题,按需选择就行:
方法1:手动给参数做URL编码
直接用URLEncoder单独编码每个参数值,把加号转成%2B,再传给URI构建工具或者RestTemplate。注意只编码参数值,别编码整个URL,不然会把?、&这些关键符号也编码了,URI就失效了。
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.client.RestTemplate; public class ManualEncodingExample { public static void main(String[] args) { String foo = "fo+o"; String bar = "ba r"; // 手动编码参数,一定要指定UTF-8字符集 String encodedFoo = URLEncoder.encode(foo, StandardCharsets.UTF_8); String encodedBar = URLEncoder.encode(bar, StandardCharsets.UTF_8); // 构建正确的URI UriComponentsBuilder ucb = UriComponentsBuilder.fromUriString("http://example.com/?foo={foo}&bar={bar}"); String finalUri = ucb.buildAndExpand(encodedFoo, encodedBar).toUriString(); // 用RestTemplate发送请求 RestTemplate restTemplate = new RestTemplate(); restTemplate.exchange(finalUri, HttpMethod.GET, null, String.class); } }
方法2:给RestTemplate配置自定义编码策略
这个方法更优雅,不用手动编码每个参数,直接给RestTemplate设置一个自定义的URI构建工厂,强制对参数值做完整编码,包括把加号转成%2B。
import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriBuilderFactory; public class ConfiguredRestTemplateExample { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); // 创建URI构建工厂,设置编码模式为「仅编码参数值」 DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory(); uriFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY); // 把这个工厂设置给RestTemplate restTemplate.setUriTemplateHandler(uriFactory); String foo = "fo+o"; String bar = "ba r"; // 直接发请求就行,参数会自动被正确编码 restTemplate.exchange( "http://example.com/?foo={foo}&bar={bar}", HttpMethod.GET, null, String.class, foo, bar ); } }
这个配置下,RestTemplate会自动把foo=fo+o编码成foo=fo%2Bo,bar=ba r编码成bar=ba%20r,完美匹配你的需求。
再说说你之前的尝试
你用UriComponentsBuilder和UriTemplate没搞定,就是因为它们默认的编码逻辑不处理加号——毕竟RFC规范里加号是空格的合法替代。只有显式指定编码策略,或者手动编码参数,才能让加号被当作普通字符转义成%2B。
内容的提问来源于stack exchange,提问作者Pablo Fernandez

