SpringBoot RestTemplate传含特殊字符查询参数时服务端接收异常问题
问题背景
我通过如下Java代码调用API接口:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(myUrl); builder.queryParam("sandwich","PB_&_J"); return restTemplate.exchange(builder.toUriString(),HttpMethod.GET,MyObject.class);
对应接口的服务端实现代码如下:
@GetMapping("myUrl") MyObject myApiFunction( @RequestParam String sandwich){ log(sandwich); //return something }
服务端无法正确解析该请求,日志中打印的sandwich参数值为'%26',而非预期的'&'。但如果打印builder.toUriString()得到请求地址http://myurl?sandwich=PB_%26_J,通过Postman直接发起该地址的请求时,服务端可以正常消费请求、正确识别参数。
问题根因
问题出在RestTemplate的默认URL处理逻辑存在二次编码问题:
UriComponentsBuilder.toUriString()生成的URL已经完成了合规编码,参数里的&被转成%26,符合URL传输规范,这也是Postman直接调用该地址能正常被服务端解析的原因。- 当你把已经编码完成的URL字符串传入
restTemplate.exchange()方法时,RestTemplate默认使用的DefaultUriBuilderFactory会对传入的字符串再次执行百分号编码:原本%26中的%会被二次编码为%25,最终服务端收到的参数实际为PB_%2526_J。服务端做一次URL解码后,拿到的值就是PB_%26_J,和你观察到的日志现象完全吻合。
修复方案
二选一即可解决问题:
- 方案1:直接传入已编码完成的
URI对象,跳过RestTemplate的字符串URL编码流程,这是最推荐的无侵入写法:
// 把toUriString()替换为toUri(),直接返回构建好的URI对象 return restTemplate.exchange(builder.toUri(), HttpMethod.GET, null, MyObject.class);
- 方案2:修改RestTemplate的URI编码模式,关闭对传入URL的自动编码逻辑:
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); // 设置编码模式为NONE,直接使用传入的已编码URL,不做二次转义 factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE); restTemplate.setUriTemplateHandler(factory);
内容的提问来源于stack exchange,提问作者Rorschach
相关产品推荐
相关产品推荐

