18888628835/Blog

URI

18888628835 opened this issue · 0 comments

URI

请求方法是通过指令的方式向服务器发送指示来指导服务器完成某个动作,常用的就是获取资源,那么怎么区分资源呢?

答案是用的是 URI 获取,也就是统一资源标识符。由于它经常出现在浏览器的地址栏,所以俗称为网址。

严格来说,URI 并不完全等同于网址,它包含 URl和 URN 两个部分,在 HTTP 中用的是 URL---统一资源定位符,由于 URL 实在太普及,所以经常把 URI 跟 URL 划上等号。

URI 非常重要,要搞懂 HTTP,就必须搞懂 URI。

URI 的格式

URI 本质上是一个字符串,这个字符串的作用是唯一地标记资源的位置或者名字,它不仅可以标记万维网的资源,也可以标记邮件系统、本地文件系统等任意资源,而资源既可以是静态文本、页面数据,也可以是Java 提供的动态服务。

URI 常用形式由 scheme、host:post、path 和 query 四个部分组成。

image.png

scheme

URI 的第一个组成部分叫 scheme,也叫协议名,它表示应该使用哪种协议来访问资源。

最常见的是 HTTP 协议,另外还有经过安全加密的 HTTPS 协议等等。

在浏览器中,如果浏览器看到地址栏上有 scheme,就会调用相应的下层 API来处理 URI。

在 scheme 的后面,固定有三个字符:‘://’,它把 scheme 和后面的部分分离开。

authority

在“://”之后,是被称为“authority”的部分,表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号。

主机可以是 IP 地址或者域名,必须要有,否则浏览器会找不到服务器。端口号有时候可以忽略,浏览器会自动根据 scheme 使用默认的端口号,常见的有 HTTP 默认端口号80,HTTPS 默认端口号是443。

path

有了 authority,后面的 path 部分标记着资源在哪个path 下,有了 scheme、主机名、端口号和 path,那么服务区就可以访问资源了。

URI 里面的 path 采用了类似文件系统的目录路径,早期的 UNIX 系统的文件目录就是采用/做分割的。

path部分必须以/开始。

实例

下面分析几个实例

http://nginx.org
http://www.chrono.com:8080/11-1
https://tools.ietf.org/html/rfc7230
file:///D:/http_study/www/

第一个 URI 比较简单,协议是 http,主机名是 nginx.org,端口号是默认的80.路径被忽略了,默认为/。也就是根目录的意思。

第二个 URI 有完整的路径和端口号。

第三个 URI 则是 HTTPS 协议,端口号为默认的443,路径为/html/rfc7230

第四个 URI 则是 file 协议,表示本地文件,后面三个斜杠的含义是
://表示分割协议和 authority的部分,剩下的/表示的是路径开头,也就是根目录下的 D 盘的/http_study/www/路径。由于 file 是 URI 的特例,它允许忽略主机名,默认为localhost

在浏览器上看到的 URI 和服务器上看到的是不一样的,例如我的掘金主页,打开F12开发者工具,点击 view source 后可以看到这样的原始请求头

image.png

服务器看到的 URI是/v1/list,对应我请求时的路径,这是因为协议名和主机名都已经出现在请求行和 Host 字段中,所以服务器只需要取删除了协议名和主机名的 URI 即可。

查询参数

使用协议名+主机名+路径的方式已经可以精确定位到网络上的资源了,但我们还想附加一些额外的修饰参数来做特定的场景,比如想要获取商品列表,根据某种规则来做分页和排序,查询参数就用上派场了。

URI 后面还有一个 query 部分,它采用?开始,表示附加的要求。

查询参数 query 有一套自己的格式,往往是多个 key=value 的字符串,这个键值对不是用 Javascript 的:连接,而是用&做连接的,浏览器和客户端都按照这个格式把长串的查询参数解析成可以理解的数据结构。

https://www.youtube.com/watch?v=FUN5rfoqLLA&t=116s

上面网址中的?v=FUN5rfoqLLA&t=116s就是查询参数 query。

URI 编码

在 URI 中只能使用 ASCII编码,如果要用到英语之外的语言,比如汉语、日语等,还有某些特殊的 URI 会在 path、query 上出现“@&?”这些字符,而这些字符在 URI 上有特殊用途,要如何区分呢?

这就要说到 URI 的编码规则了,URI引入了编码机制,对除了 ASCII编码外的字符集或者特殊字符做了特殊操作,俗称转义。

URI 的转义规则有点简单粗暴,直接把非 ASCII 码或者特殊字符转化成十六进制字节值,再在前面加上%

比如银河会被转义成%E9%93%B6%E6%B2%B3”

encodeURI('银河')
//"%E9%93%B6%E6%B2%B3"
decodeURI('%E9%93%B6%E6%B2%B3')
//"银河"
encodeURIComponent('你好')
//"%E4%BD%A0%E5%A5%BD"
decodeURIComponent("%E4%BD%A0%E5%A5%BD")
//"你好"

上面两个JavaScript函数可以对 URI进行编码和解码。

fragment

fragment 是片段标识符,也就是速成的锚点。浏览器获取资源后根据这个锚点来直接跳转到它指示的位置,不过这个片段标识符只对浏览器有用,因为它不会像查询参数一样发送给服务器处理。

https://github.com/sudheerj/reactjs-interview-questions#table-of-contents

这里的#table-of-contents就是锚点。

小结

URI 是用来唯一标记服务器上资源的字符串,通常也叫 URL。

URI 通常由 scheme、host:post、path 和 query 四个部分组成。

URI 会对@&?这些有特定用法的特殊字符以及汉字等非 ASCII 码的字符进行编码转义。