RestTemplate.delete()调用中URL编码字符串重复编码的异常问题
解决RestTemplate删除请求中URL二次编码的问题
我之前也碰到过RestTemplate这个URL编码的坑,刚好能帮到你!
问题根源
你调试到的org.springframework.web.util.DefaultUriBuilderFactory.createURI()就是关键——RestTemplate默认使用这个类处理URI构建,它会自动对URI中的变量进行URL编码。这就导致了两种错误情况:
- 如果你提前手动用
URLEncoder.encode()编码路径,框架会把已经编码的%2F中的%再次编码成%25,最终变成%252F,接口无法识别; - 如果不提前编码,框架会把路径里的
/当成路径分隔符,把test/test-cold-storage拆成两个路径段,不符合接口要求的单段编码格式。
正确解决方案
推荐按照Spring的设计思路来处理,以下几种方法都能解决问题:
1. 直接使用RestTemplate的变量替换(最推荐)
当你调用RestTemplate的方法时,把完整的项目路径作为一个单独的URI变量传入,框架会自动对这个变量里的特殊字符进行编码,不会二次处理:
String projectPath = "test/test-cold-storage"; restTemplate.delete("https://<removed>/api/v4/projects/{projectPath}", projectPath);
这样框架会自动把/编码成%2F,最终的URI就是正确的https://<removed>/api/v4/projects/test%2Ftest-cold-storage。
2. 使用UriComponentsBuilder构建URI
如果需要更精细地控制URI构建,可以用UriComponentsBuilder,它会正确处理路径段的编码:
String projectPath = "test/test-cold-storage"; UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("https://<removed>/api/v4/projects") .pathSegment(projectPath) // 这里会把整个projectPath作为一个路径段,自动编码其中的/ .build() .encode(); URI uri = uriComponents.toUri(); restTemplate.delete(uri);
或者用变量占位符的方式:
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("https://<removed>/api/v4/projects/{projectPath}") .build() .expand("test/test-cold-storage") .encode(); URI uri = uriComponents.toUri(); restTemplate.delete(uri);
3. 关闭框架的自动编码(不推荐)
如果你一定要手动编码路径,可以通过配置DefaultUriBuilderFactory关闭自动编码,但这种方式需要确保所有路径变量都已经正确手动编码,容易出错:
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(); // 设置编码模式为NONE,框架不再自动编码 uriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE); RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(uriBuilderFactory); // 此时手动编码路径不会被二次处理 String encodedProjectPath = URLEncoder.encode("test/test-cold-storage", StandardCharsets.UTF_8.toString()); restTemplate.delete("https://<removed>/api/v4/projects/" + encodedProjectPath);
验证方法
你可以继续用自定义的CustomRequestInterceptor打印请求URI,确认最终的路径是test%2Ftest-cold-storage,而不是二次编码的test%252Ftest-cold-storage或者未编码的test/test-cold-storage。
内容的提问来源于stack exchange,提问作者Joseph Gagnon
相关产品推荐
相关产品推荐

