关于URL编码的简单思考

最早

我是在看struts2处理静态资源时,看到代码中对取得的资源路径进行了url解码,具体的代码路径如下(struts2版本是2.5.20):

  • org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter第128行,
  • org.apache.struts2.dispatcher.ExecuteOperations第59行,
  • org.apache.struts2.dispatcher.DefaultStaticContentLoader第200行,
  • org.apache.struts2.dispatcher.DefaultStaticContentLoader第301行,

struts2在这里是先判断了资源是否存在,存在的话再往输出流里面写数据。

后来

我通过xxx.class.getClassLoader().getResource(“文件名”).getPath()来获取相对于classes路径的文件路径时,发现路径存在中文时会有问题,此时的中文变成了%xy%xy%xy%xy%xy%xy%xy%xy%xy这样的格式,百度后发现我前面实际上获取的是一个被url编码后的路径,必须通过url解码来获取我要的中文路径,这时我找到了一个java已有的接口:

  • java.net.URLDecoder.decode(String s, String enc)

我查阅了jdk1.6的中文文档,对它有这样的描述(实际上就是源码注释的翻译):
decode解码
上面的注释有提到一个类似编码相关的东西:application/x-www-form-urlencoded,搜了一番后我又去制定Web技术标准的中文网站发现了这个专栏:HTML URL 编码参考手册,专栏里面有这样的描述:

  • URL 编码会将字符转换为可通过因特网传输的格式。

  • URL 编码只能使用 ASCII 字符集来通过因特网进行发送。

    由于 URL 常常会包含 ASCII 集合之外的字符,URL 必须转换为有效的 ASCII 格式。

    URL 编码使用 “%” 其后跟随两位的十六进制数来替换非 ASCII 字符。

    URL 不能包含空格。URL 编码通常使用 + 来替换空格。

上面的十六进制一般指通过UTF-8编码后生成的数字的十六进制格式,再结合上面的jdk注释,大家是不是有点感觉了呢?为了进一步加深印象,我点进java.net.URLDecoder带两个参数的decode方法,看它做了点啥。我使用的是jdk1.8,由于源码没法在一张图里面完整展现,大家先自行查看。

对于这个方法的逻辑,我的简单解读如下:

  • 定义了一个boolean类型的变量needToChange,看名字应该是确定参数是否应该被改变,默认是false
  • 使用StringBuffer保存解码后的字符,初始化时StringBuffer的容量是根据第一个字符串参数的长度来确定
  • 长度大于500时,取长度的一半的整数位作为StringBuffer的容量
  • 长度不足500时,直接把长度作为StringBuffer的容量
  • 一个字节数组,存放被UTF-8编码的16进制数字

后面在一个while循环里面进行字符的转换和拼接:

while里面通过循环变量i从头依次获取字符串入参的每个位置的字符

  • 当字符是 + 时,使用一个空格来替换,将needToChange标识为true,即碰到加号就必须进行转换了——加号转空格,

  • 当字符是%时,每一组%xy这样的三个字符将生成一个字节(byte),在转换时会把%后面的xy进行十六进制转十进制的处理,通常来说一个中文字符使用UTF-8编码时会占用三个字节,比如:
    %E4%B8%AD%E5%9B%BD,这是6组%xy,除去所有的%,最终它会被转成6个字节,前面的三个字节(E4,B8,AD)实际上是对汉字"中"进行UTF-8编码后得出的,后面的则代表汉字“国”。大家可以在bejson进行验证,输入“中国”转16进制得到e4b8ade59bbd。每转换一组,变量i会加3,表示在while循环时会跳过两次,同时将needToChange标识为true。在碰到类似%x这样不完整的编码时,decode方法会直接抛出异常,因为这不是一个完整的十六进制的字节编码。最后通过new String的形式将字节数组还原成真实的字符。

  • 当碰到其他直接是ASCII 集合内的字符时,不做转换。

总结

对于url中包含中文这样的ASCII 集合之外的字符,需要进行解码处理。通常url中一个中文使用三组%xy来表示,除去特殊字符%后,一个xy实际上是被UTF-8编码后的两个十六进制格式数字,可表示为一个字节,三组xy即三个字节。最终通过new String的形式被还原成真实的字符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值