RestTemplate URL二次编码问题:原因及解决方法
问题:RestTemplate导致URL参数二次编码,API请求被拒
手动拼接的URL末尾为&timezone=Europe%2FBerlin,但通过RestTemplate发送请求时,该参数被修改为&timezone=Europe%252FBerlin(%被二次编码为%25),导致目标API拒绝请求。
原因分析
RestTemplate默认会对传入的URL字符串执行自动URL编码操作。你手动将时区参数中的/编码为%2F,相当于已经完成了一次编码;当RestTemplate处理这个预编码的URL时,会把其中的%字符当作普通字符再次编码,最终%2F就变成了%252F,造成二次编码,不符合API的参数格式要求。
修复方案
方案1:取消手动编码,让RestTemplate自动处理
直接使用原始的时区字符串Europe/Berlin,不再手动编码/,RestTemplate会自动将特殊字符编码为符合规范的格式。
修改业务代码中的getDates方法:
String getDates(String start, String end) { // 直接用Europe/Berlin,不再手动编码 return String.format("&start_date=%s&end_date=%s", start, end) + "&timezone=Europe/Berlin"; }
此时RestTemplate会自动将/编码为%2F,最终参数为&timezone=Europe%2FBerlin,符合API要求。
方案2:直接构造URI对象,绕过自动编码
如果必须使用预编码的URL,可以直接通过URI.create()构造URI对象,RestTemplate会直接使用该URI,不再执行编码操作。
修改测试代码中的调用逻辑:
@Test void test() { double lat = 52.52; double lon = 13.41; String start = "2023-04-01"; String end = "2023-04-03"; String urlStr = openMeteoService.getFullUrl(lat, lon, start, end); System.out.println(urlStr); RestTemplate restTemplate = new RestTemplate(); // 直接构造URI对象,避免二次编码 URI uri = URI.create(urlStr); OpenMeteoEntity forObject = restTemplate.getForObject(uri, OpenMeteoEntity.class); System.out.println(forObject); }
方案3:自定义UriTemplateHandler(不推荐)
通过自定义UriTemplateHandler关闭自动编码,但这种方式可能导致其他参数无法正确编码,仅适用于特殊场景:
RestTemplate restTemplate = new RestTemplate(); DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE); restTemplate.setUriTemplateHandler(factory);
验证
修改后重新运行测试,RestTemplate发送的URL参数将保持正确的Europe%2FBerlin格式,API可以正常处理请求。
内容的提问来源于stack exchange,提问作者Pioter88
相关产品推荐
相关产品推荐

