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

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图数据库就有这情形。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 基于restTemplate遇到的编码问题及解决

    目录 背景 问题一:中文乱码 描述 分析 结论 方案 总结 问题二:特殊字符串丢失 描述 分析 结论 方案 背景 之前用restTemplate做网络间的请求,没遇到过问题.今天先是出现了中文乱码的问题,而后又出现了特殊字符丢失的问题,于是查找资料及翻看源码,将问题解决也顺便记录下. 问题一:中文乱码 描述 在创建课件时,使用GET方法传递类型和标题两个参数到服务器,服务器返回一个课件编号.类型是固定数字1,不存在问题,而标题则是用户输入字符串,也就是任意字符串.发现输入汉字的时候,结果网络传输

  • 使用Spring RestTemplate 详解实践使用及拓展增强

    目录 RestTemplate 是什么? 主要类和接口 基础使用 Get获取对象或对象集合 Post 发送对象或集合 上传文件 上传多个文件 Spring RestTemplate 拓展 继承RestTemplate 拓展get方法 拓展URI处理逻辑 实际使用 思考进一步封装 RestTemplate 是什么? RestTemplate 是Spring封装的一个Rest风格http请求框架,底层可以切换成HttpClient OkHttp 或者Netty实现,用户只需要关心RestTempla

  • 将RestTemplate的编码格式改为UTF-8,防止乱码问题

    目录 RestTemplate编码格式改为UTF-8,防止乱码 RestTemplate 中文乱码配置 先看说如何解决 再看看为什么会乱码 RestTemplate编码格式改为UTF-8,防止乱码 我是在调用微信的API 的时候发现微信给我返回的用户数据不能够正常显示昵称,昵称都是乱码. //修改RestTemplate的编码格式为UTF-8 RestTemplate restTemplate = new RestTemplate(); List<HttpMessageConverter<?&

  • SpringBoot RestTemplate GET POST请求的实例讲解

    一)RestTemplate简介 RestTemplate是HTTP客户端库提供了一个更高水平的API.主要用于Rest服务调用. RestTemplate方法: 方法组 描述 getForObject 通过GET检索表示形式. getForEntity ResponseEntity通过使用GET 检索(即状态,标头和正文). headForHeaders 通过使用HEAD检索资源的所有标头. postForLocation 通过使用POST创建新资源,并Location从响应中返回标头. po

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

    目录 RestTemplate 请求url中包含百分号 会被转义成25 解决方法 RestTemplate转码bug 转码问题的背景 结论 为什么会有这个问题? RestTemplate 请求url中包含百分号 会被转义成25 最初使用RestTemplate 进行远程调用方法如下: private String getRemoteData(String url) { logger.info("Request URL :" + url + "|"); String

  • 解决Python 爬虫URL中存在中文或特殊符号无法请求的问题

    这种问题,初学者应该都会遇到,分享给大家做个参考! from urllib.parse import quote import string #解决请求路径中含义中文或特殊字符 url_ = quote(new_url, safe=string.printable); 以上这篇解决Python 爬虫URL中存在中文或特殊符号无法请求的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • SpringBoot处理请求参数中包含特殊符号

    今天写代码遇到了一个问题,请求参数是个路径"D:/ExcelFile",用postman测试时遇到的下图中的报错 java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986   at org.apache.coyote.http11.Http11InputBuffer

  • spring mvc中的@PathVariable获得请求url中的动态参数

    spring mvc中的@PathVariable是用来获得请求url中的动态参数的,十分方便,复习下: @Controller public class TestController { @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET) public String getLogin(@PathVariable("userId") String user

  • 解决RestTemplate 请求接收自定义400+ 或500+错误

    目录 RestTemplate 请求接收自定义400+ 或500+错误 场景 原因 解决办法 自定义RestTemplate的ResponseErrorHandler Spring框架中的RestTemplate处理ClientHttpResponse的方式 并不想让它抛异常 无法使用IOC注入的场景下 RestTemplate 请求接收自定义400+ 或500+错误 场景 当服务端自定义400错误返回体时,使用restTemplate 请求接收不到消息体.而我正想根据不同的错误信息做不同的操作

  • asp.net URL中包含中文参数造成乱码的解决方法

    问题: 前段时间,在系统中做了一个类似于友情链接的功能块,一直运行良好,直到有一天加了类似于以下的链接地址:http://www.****.com/user.aspx?id=水天,就出现大问题了: 1.从IE地址栏中直接输入这个地址,访问没错: 2.做一个静态页,其中包括这个超链接,点击访问也没错: 3.就是把这个链接添加到这个功能块中,点击访问那边接收到的是乱码. 一开始,被这个问题也搞得头大,在google了一把后,总算是把问题给搞清楚了,其实只要这个链接地址不经过任何编码传递是不会有问题的

  • 解决nginx代理 url重写的问题

    前后端分离,打包好的前端项目,访问后端404解决方法:nginx 增加配置 location /prod-api { proxy_pass http://xx.xx.xx.xx:端口号/; # 注意这里结尾的 / proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_h

  • 基于网址URL中特殊字符转义编码

    目录 网址URL中特殊字符转义编码 URL特殊字符转义,URL中一些字符的特殊含义,基本编码规则如下: 如果需要在URL中用到,需要将这些特殊字符换成相应的十六进制的值 预备知识 为什么需要Url编码 哪些字符需要编码 US-ASCII字符集中没有对应的可打印字符 保留字符 不安全字符 如何对Url中的非法字符进行编码 Javascript中的escape,encodeURI和encodeURIComponent的区别 安全字符不同 兼容性不同 对Unicode字符的编码方式不同 适用场合不同

  • 完美解决request请求流只能读取一次的问题

    解决request请求流只能读取一次的问题 实际开发碰到的问题 解决request请求流中的数据二次或多次使用问题 实际开发碰到的问题 springboot项目中,为了防止sql注入,采用Filter拦截器对所有请求流中的json数据进行校验,请求数据没问题则继续向下执行,在后边的代码中应用到请求参数值时,发现request中的json数据为空: 除上边描述的情况,尝试过两次从request中获取json数据,第二次同样是获取不到的. 解决request请求流中的数据二次或多次使用问题 继承Ht

  • url传递的参数值中包含&时,url自动截断问题的解决方法

    一.问题的引出 在做一个公告浏览功能时,只要通过url传递的某参数值中包含 & 或  ,就会出现问题--该变量的值无法显示. 问题定位结果: 遇到&时,该参数的值会自动截断,导致参数值传递有误. 二.问题的解决 java代码中做如下测试: String  charEncode = java.net.URLEncoder.encode("&"); System.out.println("字符& 转译后的值为:" + charEncode

随机推荐