Spring RestTemplate处理含&的查询参数时REST请求失败问题
问题回顾
你在Postman里能正常执行的请求URL:https://dev.apiwh.adidas.com/cpm/taxonomy/tags?filter=category-label eq "Body+%26+Mind"
但用Spring RestTemplate构建请求时,服务端返回400错误,提示无效的过滤字符串。从异常信息能看到,参数里的&被转成了&,变成了category-label%20eq%20%22Body%20&%20Mind%22,这就是问题根源。
原因分析
Spring的UriComponentsBuilder默认会对查询参数做HTML转义,而不是我们需要的URL编码。所以&被转成了HTML实体&,但服务端期望的是URL编码后的%26,自然就识别不了这个过滤条件了。
解决方案
这里给你三种可行的解决方法,选最适合你的就行:
方法1:手动编码参数后构建URI
先对包含特殊字符的name做URL编码,再拼接过滤参数,最后用build(true)确保只做必要的URL编码,避免HTML转义:
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; // 对name进行URL编码,处理&这类特殊字符 String encodedName = URLEncoder.encode(name, StandardCharsets.UTF_8.name()); String filterParam = "category-label eq \"" + encodedName + "\""; String url = "https://dev.apiwh.adidas.com/cpm/taxonomy/tags"; UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url) .queryParam("filter", filterParam); // build(true)参数表示已手动编码,只做URI结构的处理,不二次转义 URI uri = builder.build(true).toUri(); HttpEntity<?> entity = new HttpEntity<>(headers); HttpEntity<String> response = restTemplate.exchange( uri, HttpMethod.GET, entity, String.class);
方法2:使用UriComponentsBuilder的encode()方法
让UriComponentsBuilder帮你做正确的URL编码,指定编码格式后,它会自动把&转成%26,而不是HTML实体:
String filterParam = "category-label eq \"" + name + "\""; String url = "https://dev.apiwh.adidas.com/cpm/taxonomy/tags"; UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url) .queryParam("filter", filterParam) .encode(StandardCharsets.UTF_8); // 指定UTF-8编码进行URL转义 URI uri = builder.build().toUri(); HttpEntity<?> entity = new HttpEntity<>(headers); HttpEntity<String> response = restTemplate.exchange( uri, HttpMethod.GET, entity, String.class);
方法3:直接构造编码后的完整URL
如果不想用UriComponentsBuilder,可以手动拼接已正确编码的URL,用URI.create()直接创建URI,避免RestTemplate额外转义:
String encodedName = URLEncoder.encode(name, StandardCharsets.UTF_8.name()); // 手动拼接URL,确保所有特殊字符都已编码 String fullUrl = "https://dev.apiwh.adidas.com/cpm/taxonomy/tags?filter=category-label%20eq%20%22" + encodedName + "%22"; URI uri = URI.create(fullUrl); HttpEntity<?> entity = new HttpEntity<>(headers); HttpEntity<String> response = restTemplate.exchange( uri, HttpMethod.GET, entity, String.class);
为什么Postman能正常工作?
Postman在发送请求时,会自动对URL中的特殊字符做URL编码(把&转成%26),不会进行HTML转义,所以服务端能正确解析过滤参数。而RestTemplate默认的转义逻辑不符合这个场景,就出现了报错。
内容的提问来源于stack exchange,提问作者Damian

