又到了每周二的分享时间了,今天分享一下在网络协议中,URI的相关内容,因为在外面出差,头图没法做,就用以前的老图咯~(偷懒也这么理直气壮)
URL是什么我想大家都知道,毕竟我们每天都接触着,那URI是什么呢?
那我们先来看看,如果这世界上没有URI时,会变成什么样子呢?
没有URI的情况下,我上传了一些资料要分享给你们,你们要怎样才能下载获取呢?
首先,我得告诉你们用FTP
协议访问naonao.com
,端口是8090
然后,告诉你们登陆用户名是Naonao
,密码是Handsome
登陆成功后,你们要进入到/Naonao/Source
目录下,并且转换为二进制模式
最后再下载如何避免过帅导致的烦恼.mp4
的文件
这要不是最后的文件太吸引我,这么麻烦的步骤,我才不想去倒腾呢
可有了URI后,上面这些步骤,我们只需要在浏览器里直接输入ftp://Naonao:Handsome@naonao.com:8090/Naonao/Source/如何避免过帅导致的烦恼.mp4
这样就可以直接下载网络上的资源了
友情提示一下,上面的URI并不是一个完全正确的URI,因为最后面的中文没有进行转码,关于转码解码的问题,我们稍后再看
什么是URI?
看完上面的内容,URI解决了什么问题,我想各位心里肯定是有数了
不过在了解URI之前,我们需要先简单了解下URL与URN
URL在RFC1738(1994.12)中的定义是Uniform Resource Locator
,表示资源的所在位置,期望提供查找资源的方法
而URN在RFC2141(1997.5)中的定义是Uniform Resource Name
,期望为资源提供持久的,位置无关的标识方式,并允许简单的将多个命名空间映射到单个URN命名空间
直接说URN这种概念,有些人可能不大清楚是个什么东西,我说个例子,男生肯定清楚,比如磁力链接~嘻嘻,有没有回想起什么不可言论的东西?
我在网上找了个葫芦娃的磁力下载地址,各位围观一下,有没有觉得这东西很眼熟呢?
magnet:?xt=urn:btih:bdab9b6759950fab3c8cbde2669bea6195491034
好咯,不熟悉也没事,这也不是今天的重点,我们知道这玩意大概长城这样就好了。我们现在来看看,URI的定义是什么
URI的全名呢就是Uniform Resource Identifier
,主要用于区分资源,它包含了URL与URN的概念,主要是用于取代URL和URN的概念~
换句话说,URI可以是URL/URN,但URL/URN不一定就是URI,也就是说URI是URL/URN的超集
URI与URL的区别
虽然我们现在知道URI是URL的超集,但在网络中,URL与URI这哥俩长的实在太像了,很多时候我们傻傻分不清URL与URI到底谁是谁
我们先来看看定义的区别,URI与URL不同的部分就是Identifier
与Locator
,URI注重的是唯一标识符,而URL注重的是位置
打个简单的比喻,如果用URI来表述我们自己,那么URI就是我们的身份证号码,URL就是我们身份证上的家庭住址,通过身份证号(URI)肯定能找到我,但是你通过我的住址(URL)那就不一定能找到我了哦
再来说说资源包含了什么
资源这俩字,包含的东西就太广了,既可以是图片、文档,也可以是今天的天气
也可以是不能通过互联网访问的实体,例如人、公司
也可以是某种抽象概念,例如亲属关系或者你是不是渣男
但是要注意一点,URI并不是与资源一一对应的,一个资源是可以拥有很多个URI,但一个URI只会对应一个资源,就像我们手上有很多张银行卡,但每个银行卡对应的开户人,也只有我们自己一个人
Identifier
的实际用处就是将当前资源与其它资源区分开来的名称
通过Identifier
与Source
的含义,我们就可以很明显的感觉到URI的一个目标,它更倾向于资源提供者把自己把所拥有的资源与其它资源区分开
比如不能通过互联网访问的实体,比如人,我们就可以通过URL去定义Mine,Father,Relationship等,通过这种方式,我们就能将我们想表达的资源进行区分
URI的组成
先上张图,我们来看看URI由哪些部分组成
我们根据图片上的内容来进行分析
我们先来看最重要的三点,先拿个例子,看完例子再看下面的说明
https://naonao.com?name=naonao&age=18#page-7
Scheme
Scheme
指的就是方案,比如HTTP
,HTTPS
,FTP
等,都是可以使用的,思想不要被这些常用的协议给局限了,我们还可以自定义协议,只要服务器支持即可
Scheme
可以是由字母
,数字
,+
,-
,.
,都是允许的
注意:在Scheme
之后,必须使用://
把Scheme与后面的部分区分开来
Query
query就是查询参数,是一个可选的参数,如有有的话,那么必须要以?
开头
我们最常用的形式就是使用key=value
,比如上面的例子name=naonao
但Query并不仅仅是支持这种,它是可以支持pchar
,/
,?
等形式
?
的话大家都知道,要使用Query查询参数,那么就必须在前面加上?
,而pchar
是什么呢?这点我们想了解的话,需要去参考RFC中的详细描述,这不是今天内容的重点
fragment
fragment也是可选的,如果有的话,必须以#
开头
比如上面的示例,page-7
指向的是一个段落
它所支持的格式跟Query
所支持的格式一致
authority
authority包含了用户名与密码(user infomation),还有主机名(host),以及端口号(port)
像用户名密码这东西,我们现在基本已经不使用这种方式了,因为在URI中明文传输账号密码,实在不安全
现在还在用的,基本上也就是经常使用ftp
下载资源时我们才使用
所以我们通常只使用host:port
,即主机名+端口号的形式
主机名是不可省略的,因为一但省略,我们就找不到对应的服务器
而端口号我们却可以省略,比如HTTP
的默认端口号就是80端口,HTTPS
的默认端口号就是443端口
path
主机名后面紧跟的就是我们的path
在URI中,path
部分必须要以/
开头,所以不要把path
之前的/
误以为是前面authority
的结尾
path
也分了很多种,分别是path-abempty
、path-absolute
、path-noscheme
、path-rootless
、path-empty
- path-abempty
以/
开头的路径或空路径 - path-absolute
以/
开头,但不能以//
开头 - path-noscheme
以非:
号开头的路径 - path-rootless
相对path=noscheme
,增加允许以:
号开头的路径 - path-empty
空路径
说这么多种path
只是为了尊重文档,但也别看有这么多种类型,其实使用起来是非常简单的,综合上述五种方案,我们可以发现,限制的都是开头的字符
而我们只要不使用中文或者其它一些特殊字符作路径的开头,这样我们的路径都是合法的
所以路径这东西,我们只要根据实际情况进行填写即可
URI的编码
终于到了填坑时间
最开始我们举例说如果世上没有URI时该如何下载资源,我给出的例子URI里面带了中文,其实在URI里只能使用ASCII码
但如果我们的URI里出现了除ASCII码
以外的内容,或者是出现了URI中的用于标识的字符比如?``#``/``&
等,那么就会引起URI解析错误,那这时候该怎么办呢?
为了避免这种情况出现,URI引入了编码机制
规则非常的简单粗暴,在ASCII码
表内的特殊字符,直接就转换成ASCII码
了
对于ASCII码
以外的内容,就转换成十六进制的字节,然后在前面加上一个%
,例如空格就被转义成%20
,?
被转译成%3F
像中文这种,十六进制字节值表示不全,需要UTF-8编码才能表述完整的,就是转成十六进制(UTF-8)的格式,例如闹闹
就会被转义成%e9%97%b9%e9%97%b9
因为闹
对应的十六进制UTF-8的编码就是E9 97 B9
,然后每个字节码前面加上%
,就可以得到上述结果了
平时我们在浏览器中的地址栏中输入的URI,就算是输入中文也能正常使用,其实是浏览器在背后帮我们做了转码解码的苦逼活
这其实是一个非常友好的用户体验,不会把一些看不懂的东西直接展示给用户,也是非常值得学习的一个理念
写在最后
URI是网络协议学习中必须要弄明白的一个内容,但其实总的来说并不难,只是概念性的东西稍微多了点,理解了之后,其实就是一点点内容
你可能会问,这东西学了有什么用呢?我只能回答你,学这东西没有直接用处,但是有间接用处
比如做后台开发的,要对接接口,给的URI若不规范,那么接口调用方就无法定位到我们的资源,最后面向Google编程老半天才解决
又或者做前端开发的,接口调用不规范,比如GET调用时query参数写错,那自然也调不通后台给的接口
又比如拿到一个不熟悉的项目,通过浏览器的Network就可以分析到用了哪些资源,依赖了什么页面和接口,但连URI都看不懂,那就只能问同事了,问完后还要被人一顿嫌弃
虽然遇到的这些问题都能面向Google编程或者问同事解决,但是在查资料或者咨询的同时,浪费的是我们的时间以及同事的时间