解决RestTemplate 请求url中包含百分号 会被转义成25的问题

网友投稿 2118 2022-11-27

解决RestTemplate 请求url中包含百分号 会被转义成25的问题

目录RestTemplate 请求url中包含百分号 会被转义成25解决方法RestTemplate转码bug转码问题的背景结论为什么会有这个问题?

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 传入:

privatblQuyAdxe 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源码实现后,发现是客户端http://的转码协议和服务端的解码协议不匹配导致。

经反复测试和严重,这个问题只有参数中带有空格时才会有,其他字符都不有,比如http://: / * & 这类特殊字符都没这问题。

最后的解决方案是替换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 Resp doGet(String url, Req request, Class responseType) throws Exception {

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);

Map parameters = (Map)request;

for (Map.Entry entry : parameters.entrySet()) {

builder.queryParam(entry.getKey(), Objects.toString(entry.getValue(), ""));

}

return restTemplhttp://ate.getForObject(builder.build(false).toUri(), responseType);

}

为什么会有这个问题?

根源在于java语言的URLEncode类只能适用于早期的RFC协议,通常spring开发的服务端是兼容这种模式的。

新版的RFC协议会把+号当成关键字不再反转成空格,这通常体现在新技术上,比如目前用的tigergraph图数据库就有这情形。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:thinkphp5 Barcodegen 生成条形码
下一篇:swoole 初试教程 udp服务
相关文章

 发表评论

暂时没有评论,来抢沙发吧~