zoukankan      html  css  js  c++  java
  • 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图数据库就有这情形。

    RFC原文依据如下:

    http://www.faqs.org/rfcs/rfc2396.html

  • 相关阅读:
    【web 安全测试Tools】BurpSuite 1.7.32及注册机【无后门版】
    【Kail 学习笔记】Dmitry信息收集工具
    【web 安全测试思路】图形验证码对服务器的影响
    【Kail 学习笔记】自用KAIL更新源
    ASP.NET动态网站制作(23)-- ADO.NET(2)
    ASP.NET动态网站制作(22)-- ADO.NET(1)
    ASP.NET动态网站制作(21)-- C#(4)
    ASP.NET动态网站制作(20)-- C#(3)
    ASP.NET动态网站制作(19)-- C#(2)
    ASP.NET动态网站制作(18)-- jq作业讲解及知识补充
  • 原文地址:https://www.cnblogs.com/geektcp/p/10623396.html
Copyright © 2011-2022 走看看