解决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

标签:RestTemplate,请求url,百分号,转义
0
投稿

猜你喜欢

  • Java实现雪花算法(snowflake)

    2022-10-27 03:43:23
  • JNI方法实现图片压缩(压缩率极高)

    2021-08-07 11:32:55
  • Java基于Tcp协议的socket编程实例

    2022-03-08 00:04:13
  • Android13 加强Intent filters 的安全性

    2022-06-17 03:15:55
  • Android itemDecoration接口实现吸顶悬浮标题

    2023-03-14 00:58:31
  • Androidstudio调用摄像头拍照并保存照片

    2022-01-23 18:33:57
  • 聊聊Spring Cloud Gateway过滤器精确控制异常返回问题

    2022-06-23 01:04:14
  • 浅谈Spring事务传播行为实战

    2022-07-04 01:54:44
  • 关于C# Math 处理奇进偶不进的实现代码

    2023-03-25 09:30:29
  • Android(2.2/2.3系统)Gallery解决默认和横竖屏切换选中状态问题

    2022-09-30 19:06:18
  • Java操作FTP实现上传下载功能

    2021-12-07 18:35:04
  • 深入了解Java核心类库--Math类

    2023-08-19 01:06:21
  • Android实现屏幕旋转方法总结

    2023-04-01 19:37:31
  • java验证电话号码的方法

    2023-04-01 21:44:41
  • Java 自定义Spring框架以及Spring框架的基本使用

    2021-05-29 19:35:57
  • Android仿QQ圆形头像个性名片

    2021-08-24 02:40:46
  • Android之复选框对话框用法实例分析

    2023-10-03 05:07:03
  • spring boot 动态生成接口实现类的场景分析

    2022-12-14 05:09:33
  • Spring Boot应用Docker化的步骤详解

    2023-10-12 11:47:36
  • Android实现上传文件功能的方法

    2022-01-18 11:01:02
  • asp之家 软件编程 m.aspxhome.com