RestTemplate源码剖析:Encode

栏目: 编程工具 · 发布时间: 6年前

内容简介:业务方经过某些业务处理之后,带过来了一系列参数。其中,有个url参数供回调使用,但这个url经业务方处理后很特殊,带过来回调时频频出错,无法正常回调给业务方。于是,通过分析部分源码,剖析一下回调的流程。说到url的回调,很容易联想到decode、encode,即编码解码操作。按照如上所说,业务方带过来了处理后的url,另附上说明,url无需解码,直接回调即可,但事情往往没那么顺利。不管是使用spring5 webclient,还是restTemplate以get请求回调业务方,均会出错。由于最终使用了res

业务方经过某些业务处理之后,带过来了一系列参数。其中,有个url参数供回调使用,但这个url经业务方处理后很特殊,带过来回调时频频出错,无法正常回调给业务方。于是,通过分析部分源码,剖析一下回调的流程。

编码 解码

说到url的回调,很容易联想到decode、encode,即编码解码操作。

通常来说,需要编码操作即意味着不适合直接传输,某些字符可能有歧义,如中文、特殊字符等等。
而通过编码之后(如 utf-8),传输给服务端,服务端自行解码,便不会出现一系列乱码问题。
复制代码

说明

按照如上所说,业务方带过来了处理后的url,另附上说明,url无需解码,直接回调即可,但事情往往没那么顺利。不管是使用spring5 webclient,还是restTemplate以get请求回调业务方,均会出错。由于最终使用了restTemplate解决了问题,对此本次剖析一下restTemplate。

注:WebClient同样可以解决问题,剖析restTemplate的因由在于综合分析了项目的引用和耦合度,不适合改动webclient模块,故而拓展了restTemplate。

剖析

  1. 先写个极其简单的单测入口,进行RestTemplate的源码分析。

    RestTemplate源码剖析:Encode
  2. 紧接着集中分析RestTemplate类

  • 请求头、请求体是由RequestCallback来处理的,请求结果是由ResponseExtractor来处理。

    RestTemplate源码剖析:Encode
  • RestTemplate默认已经初始化添加了许多对象读写转换器。

    RestTemplate源码剖析:Encode
  1. 进入execute这个重要的方法继续分析。

    RestTemplate源码剖析:Encode
  2. 可以看出,先用UriTemplateHandler构建URI,再走关键逻辑。

  • UriTemplateHandler build URI

    RestTemplate源码剖析:Encode
  • 通过构造函数的初始化,可以看到使用的是默认builder工厂

    RestTemplate源码剖析:Encode
    RestTemplate源码剖析:Encode
  • 从类继承图可以看出DefaultUriBuilderFactory实现了UriBuilderFactory,继承了UriTemplateHandler

    RestTemplate源码剖析:Encode
  • expand(String var1, Object... var2)是UriTemplateHandler接口的方法

    RestTemplate源码剖析:Encode
  1. 继续分析UriTemplateHandler接口expand方法源码
    RestTemplate源码剖析:Encode
    RestTemplate源码剖析:Encode
  • 到这里我们可以发现DefaultUriBuilderFactory默认builder工厂存在一个内部类DefaultUriBuilder

    RestTemplate源码剖析:Encode
  • 接着进入分析一下UriComponentsBuilder类的源码,从类名可以猜想到这个UriComponentsBuilder构建器可能用于创建UriComponents实例

    RestTemplate源码剖析:Encode
  • 顾名思义,UriComponents包含了构成URI的组件,以及一系列的getter and setter方法

    RestTemplate源码剖析:Encode
  • 继续着刚才初始化UriComponentsBuilder的方法

    RestTemplate源码剖析:Encode
  • 符合了内置的url pattern之后继续构建UriComponentsBuilder,通过构造器可以看出默认字符集是utf-8

    RestTemplate源码剖析:Encode
    RestTemplate源码剖析:Encode
  • 可以清晰看出初始化之后的构建器

    RestTemplate源码剖析:Encode
  1. 接下来出来外层的包裹,分析build方法
    RestTemplate源码剖析:Encode
  • 分析DefaultUriBuilderFactory build的过程 划重点!!! 因为uriVariableValues为空,不关心这个expand方法,此时注意build方法。

    RestTemplate源码剖析:Encode
  • 可以看到,build UriComponents,有个encoded参数,默认为false先不透露具体细节,只需先记住构建这次请求的UriComponents,encoded参数为false!!!

    RestTemplate源码剖析:Encode
  • 接着看encoded参数为false,会影响到哪些参数值 由encodedfalse可得到UriComponentsBuilder.EncodingHint为NONE

public UriComponents build(boolean encoded) {
      return this.buildInternal(encoded ? UriComponentsBuilder.EncodingHint.FULLY_ENCODED : (this.encodeTemplate ? UriComponentsBuilder.EncodingHint.ENCODE_TEMPLATE : UriComponentsBuilder.EncodingHint.NONE));
}
复制代码
  • 再接着就是构造HierarchicalUriComponents
    RestTemplate源码剖析:Encode
HierarchicalUriComponents uric = new HierarchicalUriComponents(this.scheme, this.fragment, this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, hint == UriComponentsBuilder.EncodingHint.FULLY_ENCODED);
复制代码
  • 最后可以看到HierarchicalUriComponents.EncodeState为RAW 这里划重点!!!
    RestTemplate源码剖析:Encode
  1. 继续看外层的包裹,构建完之后的UriComponents
    RestTemplate源码剖析:Encode
  • 继续分析createUri,由于匹配到是默认的URI_COMPONENT,则走encode方法

    RestTemplate源码剖析:Encode
  • 本次剖析很重要的一个方法,终于要接近问题的真相了!!!

    RestTemplate源码剖析:Encode
  • 从上个提示重要的剖析点得知,构建UriComponents,encoded参数默认为false,进而从源码可得知,HierarchicalUriComponents.EncodeState的值为RAW。那么就会走下面的encodeUriComponent的方法(至于怎么encode暂不在分析范围内,看源码貌似是用字节流操作来encode,有兴趣可以阅读)

    RestTemplate源码剖析:Encode
  • 接着对segment,queryParams等进行编码

    RestTemplate源码剖析:Encode
  • 参数编码的细节,勾出来的是 Java 8的Function,实现就不贴了,源码比较简单

    RestTemplate源码剖析:Encode
  • 最终,通过比对参数ext_info的值,便得知参数被主动encode了

    RestTemplate源码剖析:Encode

解决方案

ok~~~ 分析完后,知道问题的根源在不该被encode的URL却在restTemplate的深处被动encode了,因此导致了回调的失败。既然明确问题所在,也分析过源码,解决起来就很简单了。如下:

构建UriComponentsBuilder,builder构建时传入encoded值为true,并转URI形式入参,问题解决。

RestTemplate源码剖析:Encode

枚举状态总结

为了帮助大家记忆,简单理一下状态。

  1. UriComponentsBuilder.EncodingHint

UriComponentsBuilder构建器有个枚举EncodingHint,UriComponentsBuilder构建时encoded默认为false。

  • 若encoded为false,则看有没有提供另外的encodeTemplate; 若有则值为ENCODE_TEMPLATE,否则为NONE
  • 若encoded为true时,值为FULLY_ENCODED
  1. HierarchicalUriComponents.EncodeState

HierarchicalUriComponents组件有个枚举EncodeState,其值的影响在于以上的EncodingHint。 源码的encode过滤也在于这个组件的EncodeState值!!!

  • 若EncodingHint为FULLY_ENCODED,则EncodeState为FULLY_ENCODED
  • 若EncodingHint不为FULLY_ENCODED(ENCODE_TEMPLATE或NONE),则EncodeState为RAW

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大数据技术原理与应用

大数据技术原理与应用

林子雨 / 人民邮电出版社 / 2015-8-1 / 45.00

大数据作为继云计算、物联网之后IT行业又一颠覆性的技术,备受关注。大数据处不在,包括金融、汽车、零售、餐饮、电信、能源、政务、医疗、体育、娱乐等在内的社会各行各业,都融入了大数据的印迹,大数据对人类的社会生产和生活必将产生重大而深远的影响。 大数据时代的到来,迫切需要高校及时建立大数据技术课程体系,为社会培养和输送一大批具备大数据专业素养的高级人才,满足社会对大数据人才日益旺盛的需求。本书定......一起来看看 《大数据技术原理与应用》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具