Spring Boot之RestTemplate在URL中转义字符禁止转义的问题解决

问题的提出

基于resttemplate类进行文件下载,但是不幸的url地址中有特殊的转义字符,如果使用resttemplate的方法的话,其默认会进行转义。
原始字符串:

http://www.xx.com/image-checker/train_mean.txt?Expires=3678172563&Signature=2FqOFfzePCjESlKMqiGc9V8C9Es%3D

在RestTemplate转义的字符中:

http://www.xx.com/image-checker/train_mean.txt?Expires=3678172563&Signature=2FqOFfzePCjESlKMqiGc9V8C9Es%253D

在这个url中%是特殊的字符,并转义为: %25. 但是被转义之后的URL不是正确的URL地址,程序会报出错误的400 BadRequest请求。

尝试与分析

在获取上述信息之后,尝试进行各类处理方法。由于问题解决在RestTemplate中会针对url的string进行encode,所以这个方式的处理都会出现。
主要使用的方式有:

  • StringBuffer/StringBuilder,拼接字符(无效)
  • URLBuilder生成URI (无效)
    在这里注意到URI是不行进行encode的,这是一个发现。
  • UriComponent构建uri
  • UriComponentBuilder

最终是通过UriComponentBuilder来完美解决问题的,这个是后话。
在RestTemplate的源码分析中发现,其会针对入口的URL String类型进行编码,摘取的代码如下:
代码位置: org.springframework.web.client.RestTemplate之683 ~~ 700行

@Override
    @Nullable
    public  T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
            @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables)
            throws RestClientException {

        URI expanded = getUriTemplateHandler().expand(url, uriVariables);
        return doExecute(expanded, method, requestCallback, responseExtractor);
    }

    @Override
    @Nullable
    public <T> T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback,
            @Nullable ResponseExtractor responseExtractor) throws RestClientException {

        return doExecute(url, method, requestCallback, responseExtractor);
    }

从上述代码中可以发现,其基于URI的方式是不进行encode处理,就是说其将encode操作放入了URI中。

问题的解决

在UriComponentBuilder中提供创建URI的方式,这里就需要看看其是否能够满足要求:

UriComponentsBuilder builder = UriComponentsBuilder
                .fromHttpUrl("http://xxx.com/image-checker/train_mean.txt").queryParam("Expires", "3678172563").queryParam("Signature", "2FqOFfzePCjESlKMqiGc9V8C9Es%3D");
log.info("Real File Name:{}, URL:{}", "filetext", builder.build(true).toUri());     

从上述代码中,会发现%并未被转义,而是被正确的使用了。

问题的源码分析

经过分析,发现真正进行UriString构建的操作在org.springframework.web.util.HierarchicalUriComponents类中的toUriString()方法中,其直接进行的字符串的拼接,而非进行encode。
感兴趣的读者可以自行进行阅读代码。

参考资料

https://stackoverflow.com/questions/28182836/resttemplate-to-not-escape-url

你可能感兴趣的:(Java技术,服务化与Spring,Cloud,Spring,Boot实战)