解决RestTemplate 请求url中包含百分号 会被转义成25的问题
作者:toneylyx 发布时间:2022-11-01 22:59:51
RestTemplate 请求url中包含百分号 会被转义成25
最初使用RestTemplate 进行远程调用方法如下:
private String getRemoteData(String url) {
logger.info("Request URL :" + url + "|");
String resp = rest.getForObject(url, String.class);
logger.info("Response result : " + resp.toString());
return resp;
}
但发现请求结果一直为空。
最后发现由于我们的业务场景中,请求参数包含中文要求按指定规则转码,导致请求url中包含% ,而RestTemplate会自动调用encode方法进行转义,将%转义成了%25 。
解决方法
自建URI 传入:
private String getRemoteData(String url) {
logger.info("Request URL :" + url + "|");
String resp = null;
try {
URI uri = new URI(url);
resp = rest.getForObject(uri, String.class);
} catch (URISyntaxException e) {
logger.error("Create URI Exception !");
}
logger.info("Response result : " + resp.toString());
return resp;
}
RestTemplate转码bug
发现一个关于HTTP的Get请求的罕见bug。
转码问题的背景
需要向tigergraph服务端发送一个复杂的get请求,参数只有一个,但是参数的值是一个复杂json
服务端收到的值始终是不正常的值。观察发现,不正常地方在于服务端本应解析为空格的地方都变成了加号(+)。
以为是代码写得有问题,然后使用HTTPclient的原生的方式发起请求:
public static String doGet(String url) throws Exception{
HttpGet get = new HttpGet(url);
return doMethod(get);
}
private static String doMethod(HttpRequestBase method)throws Exception{
CloseableHttpResponse response = null;
CloseableHttpClient client;
HttpClientBuilder hcb = HttpClientBuilder.create();
HttpRequestRetryHandler hrrh = new DefaultHttpRequestRetryHandler();
HttpClientBuilder httpClientBuilder = hcb.setRetryHandler(hrrh);
client = httpClientBuilder.build();
method.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
method.addHeader(HTTP.CONTENT_TYPE, APPLICATION_JSON);
RequestConfig.Builder confBuilder = RequestConfig.custom();
confBuilder.setConnectTimeout(CONNECT_TIMEOUT);
confBuilder.setConnectionRequestTimeout(REQUEST_TIMEOUT);
confBuilder.setSocketTimeout(SOCKET_TIMEOUT);
RequestConfig config = confBuilder.build();
method.setConfig(config);
response = client.execute(method);
int code = response.getStatusLine().getStatusCode();
String result = EntityUtils.toString(response.getEntity());
response.close();
client.close();
return result;
}
得到结果还是这个问题,使用Assured测试工具构建http请求也有这问题。
结论
后来仔细检查了URLEncode.encode方法和RestTemplate源码实现后,发现是客户端的转码协议和服务端的解码协议不匹配导致。
经反复测试和严重,这个问题只有参数中带有空格时才会有,其他字符都不有,比如: / * & 这类特殊字符都没这问题。
最后的解决方案是替换URL串的转码后的字符串中的空格为%20,然后使用http client原生的请求方式。
第二个解决方案是使用RestTemplate的UriComponentsBuilder类,使用(builder.build(false).toUri()获得URL,参数必须是false才会把空格转成%20
/** * urlencode转码不能随便用,因为她会把空格转换成+号,而不是标准的%20字符。 * 对于spring构建的服务端不会有这个问题。但我在tiger服务器上遇到这种问题。 * 所以urlencode只适用于服务端支持的协议是RFC1738 * 如果服务端只支持RFC 2396标准,那么服务端解码时,会把加号+当成保留字符,而不转码 * */
@Override
@SuppressWarnings("all")
public <Req, Resp> Resp doGet(String url, Req request, Class<Resp> responseType) throws Exception {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
Map<String, Object> parameters = (Map<String, Object>)request;
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
builder.queryParam(entry.getKey(), Objects.toString(entry.getValue(), ""));
}
return restTemplate.getForObject(builder.build(false).toUri(), responseType);
}
为什么会有这个问题?
根源在于Java语言的URLEncode类只能适用于早期的RFC协议,通常spring开发的服务端是兼容这种模式的。
新版的RFC协议会把+号当成关键字不再反转成空格,这通常体现在新技术上,比如目前用的tigergraph图数据库就有这情形。
来源:https://blog.csdn.net/toneylyx/article/details/98088637


猜你喜欢
- 看门见山1.java中replace API:replace(char oldChar, char newChar):寓意为:返回一个新的字
- 本文实例讲述了Java上传文件进度条的实现方法。分享给大家供大家参考,具体如下:东西很简单,主要用到commons-fileupload,其
- 前言如今发短信功能已经成为互联网公司的标配,本篇文章将一步步实现java发送短信考察了许多提供短信服务的三方,几乎所有都需要企业认证才可以使
- 创建一个类,在该类的主方法中创建标准输入流的扫描器对象,提示用户输入一个整数,并通过扫描器的方法来接受这个整数,然后通过三元运算符判断该数字
- 一、泛型的基本概念java与c#一样,都存在泛型的概念,及类型的参数化。java中的泛型是在jdk5.0后出现的,但是java中的泛型与C#
- 本文实例为大家分享了shiro整合springboot前后端分离的具体代码,供大家参考,具体内容如下1、shiro整合springboot的
- java生成json时产生栈溢出错误环境java + hibernate +html本来,java中使用json事件很正常的事,但小心有的地
- SpringBoot停止启动时测试检查rabbitmq问题在Springboot项目中配置rabbitmq后,总是在每次启动时自动测试MQ的
- Groovy 简介Groovy 是构建在 JVM 上的一个轻量级却强大的动态语言,它结合了 Python、Ruby 和 Smalltalk
- 委托给了C#操作函数的灵活性,我们可使用委托像操作变量一样来操作函数,其实这个功能并不是C#的首创,早在C++时代就有函数指针这一说法,而在
- 开始我用List<泛型>接受json串,如下,结果list内并非泛型对象,而是JSONObject对象。这样在遍历的时候就报了转
- 👉实践过程😜常用属性因为Seekbar继承自ProgressBar,所以ProgressBar支持的XML属性SeekBar都适用。【and
- 前言之前做移动端开发,都不清楚WebService是啥东东,现在接触c#,项目中有三处WebService调用,就不得不与其打交道了,最近碰
- 前言网上SSO的框架很多,此篇文章使用的是自写的SSO来实现简单的登录授权功能,目的在于扩展性,权限这方面,自写扩展性会好点。提示:以下是本
- 这篇文章主要介绍了Spring boot @RequestBody数据传递过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有
- Java中java.io包为我们提供了输入流和输出流,对文件的读写基本上都依赖于这些封装好的关于流的类中来实现。前段时间遇到了以下两种需求:
- 一、配置逆向generatoe.xml<?xml version="1.0" encoding="UTF
- ijkPlayer 编译全格式支持 .so库基本步骤拉取docker镜像//命令行执行如下命令即可 docker pull adajqd/i
- 其实项目网上有很多了,但是教程比较详细的没多少,今天分享的项目从安装部署到代码具体功能都有很详细都说明eladmin 是一款基于 Sprin
- 1、添加spring相关jar包2、配置ehcache jar包。3、添加ehcache mybatis 适配器jar包(在mybatis官