JAVA中的URL和URI类的使用出现的非法字符问题

今天在利用URI来创建文件对象的时候出现了异常

说是urI中包含了非法字符,一看发现URI中有一个空格字符

RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符,这些字符被称为未保留字符

以及所有保留字符。

Url中只允许使用可打印字符。US-ASCII码中的10-7F字节全都表示控制字符,这些字符都不能直接出现在Url中。同时,对于80-FF字节(ISO-8859-1),由于已经超出了US-ACII定义的字节范围,因此也不可以放在Url中。

  保留字符

Url可以划分成若干个组件,协议、主机、路径等。有一些字符(:/?#[]@)是用作分隔不同组件的。例如:冒号用于分隔协议和主机,/用于分隔主机和路径,?用于分隔路径和查询参数,等等。还有一些字符(!$&'()*+,;=)用于在每个组件中起到分隔作用的,如=用于表示查询参数中的键值对,&符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进行编码。

RFC3986中指定了以下字符为保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]

  不安全字符

还有一些字符,当他们直接放在Url中的时候,可能会引起解析程序的歧义。这些字符被视为不安全字符,原因有很多。

  • 空格:Url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理Url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉。
  • 引号以及<>:引号和尖括号通常用于在普通文本中起到分隔Url的作用
  • #:通常用于表示书签或者锚点
  • %:百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码
  • {}|\^[]`~:某一些网关或者传输代理会篡改这些字符

那么我们就知道了,因为URI中有非法字符,为了避免引起歧义,要进行转义才可以,然后我就想当然的请出了URLEncoder,然后发现,错的严重了。

这下连协议都解析不到了,为什么?因为URLEncoder将我们URL中合法的保留符也给转义了(其会将传入的字符串中的所有非保留字符之外的字符进行转义),就得到了上面的结果,那要怎么办?难道非得要将文件名部分取出来对其进行Encoding?可以是可以,但是感觉不够灵活 ,有点麻烦。

 就此我发现,我对URLEncoder的理解出现了问题,此前一直以为只要URL中有非法字符,直接使用该类进行一次编码就可以了,之前一直这样使用也没有问题,因为此前一直转义的是URL的query部分,且只包含一个参数,对前面的path和host没有造成影响,不会对URL中的保留字符出现什么影响从而造成URL解析错误(保留字符被转义了就会导致URL格式错误,URL格式的解析就是靠保留字符进行划分)。

URLEncoder的编码就是将你给定的字符中的每一个非保留字符都进行编码了,对其中的出现的字母"a-zA-Z"、数字"0-9"、特殊字符-_.~等不会进行编码,但是遇到保留字符,非法字符等就会进行编码,所以我们上面把整个URL进行编码,就把“/”也编码了,最终就导致格式解析出现问题。

所以说,我们在使用URLEncoder的时候,要注意避免其将URL本身的保留字符给转义了,而是去转义非法字符和不安全字符

那JAVA中有什么灵活的方式能解决上面的问题呢?

之所以出现上面的问题是因为uri在解析字符串的时候出现了非法字符,导致其解析失败。我们创建的创建的每一个URI对象其都会去解析成出URL中的几个部分。

但是在解析过程中出现非法字符的话,就导致了解析异常,所以我们需要对URL中的非法字符进行转义

但是我们可能也不清楚到底在我们的URI的哪个位置会出现非法的字符,所以想要进行编码也不知道去编码哪个部分(host,path,query等部分),又或者说我们直接对每一个部分都进行一次编码

URL url = new URL("file:///D:/tomcat/a .mp4");
// 利用URL解析出来的几个部分直接创建URI,这样URI就不会进行解析了
// 直接就利用了你给定的部分
URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery());

之所以能像上面这样是因为Java中的URL类在解析URL的时候,其不会去检测每个部分具体的字符,其只是根据保留字符解析出一个URL的几部分。对于我们URL每一个部分之中的非法字符其并不会去扫描(当然,你的非法字符不能是保留字符,否则会导致URL解析每个部分的时候出错,也会出现异常,因为保留字符是区分一个URL的几个部分的关键)

URL类中解析一个URL的类是URLStreamHandler这个类,有兴趣的可以去debug一下

所以说最终的解决办法其实还是要去避免在uri中出现上面特殊的字符

发布了162 篇原创文章 · 获赞 44 · 访问量 8846

猜你喜欢

转载自blog.csdn.net/P19777/article/details/103460910