目录

  1. 概述
  2. 资源类型
  3. 定位资源
    1. URI
    2. URL
    3. URN
  4. URL 的语法
    1. 方案
    2. 主机与端口号
    3. 用户名和密码
    4. 路径
    5. 参数
    6. 查询字符串
    7. 片段
  5. URL 快捷方式
    1. 相对 URL
      1. 基础 URL(Base URL)
      2. 解析相对引用
    2. 自动扩展 URL
      1. 主机名扩展
      2. 历史扩展
    3. URL 中的字符处理
    4. URL 字符集
    5. 编码机制
    6. 字符限制
    7. 其他
  6. 总结

概述

❓什么是资源?

互联网最初搭建的目的就是能够让使用者之间相互共享资源,我们可以认为计算机网络中的任何东西都是资源。但是,日常生活中我们接触最多的就是 Web 应用程序,所以我们的关注点也是 Web 资源

最简单的 Web 资源就是 Web 服务器文件系统中的静态文件,这些文件可以是任意格式,如:文本文件(TXT)、HTML 文件、微软的 Word 文件、Adobe 的 Acrobat 文件、 JPEG 图片文件、AVI 电影文件等等。

🎶需要注意的是,资源不一定非得是静态文件,资源还可以是根据需要生成内容的软件程序(动态文件)

资源类型

❓HTTP 对每种要通过 Web 传输的对象都打上了名为 MIME 类型的数据格式标签,为什么要设计MIME类型?

最初设计 MIME (Multipurpose Internet Mail Extension,多用途因特网邮件扩展)是为了解决在不同的电子邮件系统之间搬移报文时存在的问题。MIME 在电子邮件系统中工作得非常好,因此 HTTP 也采纳了它,用它来描述并标记多媒体内容。Web 服务器会为所有 HTTP 对象数据附加一个 MIME 类型。当 Web 浏览器从服务器中取回一个对象时,会去查看相关的 MIME 类型,看看它是否知道应该如何处理这个对象

定位资源

每个 Web 服务器资源都有一个名字,这样客户端就可以说明它们感兴趣的资源是什么了。服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI)。URI 就像因特网上的邮政地址一样,用于在计算机的世界内唯一标识并定位信息资源

URI

URI 是一类通用的资源标识符,由两个主要的子集 URLURN 构成。URL 是通过描述资源的位置来标识资源的,而 URN 则是通过名字来识别资源的,与资源当前所处位置无关

✨URI 有两种形式,分别称为 URL 和 URN

URL

URL 是浏览器寻找信息时所需的资源位置。URL 描述了一台特定服务器上某资源的特定位置,通过 URL 可以明确说明如何从一个精确、固定的位置获取资源。常见的 URL 实例如下:

URL描述
http://www.oreilly.com/index.htmlO’Reilly & Associates 公司的主 URL
https://pineapple-man.github.io/assets/images/logo.jpg我博客 logo 的 URL
ftp://joe:tools4u@ftp.joes-hardware.com/locking-pliers.gif用 FTP 作为访问协议的 locking-pliers.gif 图片文件的 URL

大部分 URL 都遵循如下这样一种标准格式,这种格式包含三个部分

1
scheme://PATH/TO/HOST/:PORT/PATH/TO/RESOURCE
部分含义
scheme://URL 的第一部分被称为方案(scheme),说明了访问资源所使用的协议类型。这部分通常是 HTTP 协议(http://)以告知 Web 客户端怎样访问资源
PATH/TO/HOST/:PORT第二部分给出了服务器的因特网地址(比如,www.joes-hardware.com)告知 Web 客户端资源位于何处
/PATH/TO/RESOURCE指定了 Web 服务器上的某个资源路径(比如,/specials/saw-blade.gif)路径说明了请求的是服务器上哪个路径下的本地资源

URL 可以通过 HTTP 之外的其他协议来访问资源。它们可以指向因特网上的任意资源,或者个人的 E-mail 账户,比如mailto:president@whitehouse.gov,或者通过其他协议(比如 FTP 协议)访问的各种文件:ftp://ftp.lots-o-books.com/pub/complete-price-list.xls

URL 提供了一种统一的资源命名方式,大多数 URL 都有同样的:scheme://PATH/TO/HOST/:PORT/PATH/TO/RESOURCE 结构。因此,对网络上的每个资源来说,命名资源的方法只有一种,这样不管是谁都可以用名字来找到这个资源

URN

URI 的第二种形式就是统一资源名(URN),URN 是作为特定内容的唯一名称使用的,与资源所在地无关。使用这些与位置无关的 URN,就可以将资源四处搬移,通过 URN 可以用同一个名字通过多种网络访问协议来访问资源

URN 仍然处于试验阶段,还未大范围使用

URL 的语法

URL 提供了一种定位因特网上任意资源的手段,但这些资源是可以通过各种不同的方案(比如 HTTP、FTP、SMTP)来访问的,因此 URL 语法随方案的不同而有所不同

🤔这是不是意味着每种不同的 URL 方案都会有完全不同的语法呢?

实际上,不是的。 大部分 URL 都遵循通用的 URL 语法,而且不同 URL 方案的风格和语法都有不少重叠,多数 URL 方案的 URL 语法都建立在这个由 9 部分构成的通用格式上:

1
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

几乎没有哪个 URL 中包含了所有这些组件,URL 最重要的三个部分是方案(Scheme)主机(host)路径(path)

组件描述默认值
方案访问服务器以获取资源时要使用哪种协议
用户某些方案访问资源时需要的用户名匿名
密码用户名后面可能要包含的密码,中间由冒号(:)分隔<E-mail 地址 >
主机资源宿主服务器的主机名或点分 IP 地址
端口资源宿主服务器正在监听的端口号。很多方案都有默认端 口号(HTTP 的默认端口号为 80)每个方案特有
路径服务器上资源的本地名,由一个斜杠(/)将其与前面的 URL 组件分隔开来。路径组件的语法是与服务器和方案有关的(本章稍后会讲到 URL 路径可以分为若干个段,每段都可以有其特有的组件。
参数某些方案会用这个组件来指定输入参数。参数为名 / 值对。 URL 中可以包含多个参数字段,它们相互之间以及与路径 的其余部分之间用分号(;)分隔
查询某些方案会用这个组件传递参数以激活应用程序(比如数 据库、公告板、搜索引擎以及其他因特网网关)。查询组件的内容没有通用格式。用字符?将其与 URL 的其余 部分分隔开来
片段一小片或一部分资源的名字。引用对象时,不会将 frag 字 段传送给服务器;这个字段是在客户端内部使用的。通过 字符“#”将其与 URL 的其余部分分隔开来

方案

方案也就是通常所说的众多协议(HTTPHTTPSFTPJDBC),方案组件必须以一个字母符号开始,由第一个 : 符号将其与 URL 的其余部分隔开。方案名是大小写无关的,因此无论是http://www.joes-hardware.com和``HTTP://www.joes-hardware.com`是等价的

主机与端口号

要想在因特网上找到资源,应用程序要知道是:在什么地方可以找到能对目标资源进行访问的服务器,URL 的主机和端口组件提供了这两组信息。主机组件标识了因特网上能够访问资源的宿主机器。可以用上述主机名(www.joes-hardware.com),或者 IP 地址来表示主机名。

用户名和密码

很多服务器都要求输入用户名和密码才会允许用户访问数据(如今使用的不多,大部分会在前后端程序中进行认证操作,不在 URL 上限制用于)。FTP 服务器就是这样一个常见的实例,这里有几个例子:

ftp://ftp.prep.ai.mit.edu/pub/gnu

ftp://anonymous@ftp.prep.ai.mit.edu/pub/gnu

ftp://anonymous:my_passwd@ftp.prep.ai.mit.edu/pub/gnu

http://joe:joespasswd@www.joes-hardware.com/sales_info.txt

第一个例子没有用户或密码组件,只有标准的方案、主机和路径。如果某应用程序使用的 URL 方案要求输入用户名和密码,但用户没有提供,它通常会插入一个默认的用户名和密码

如果向浏览器提供一个 FTP URL,但没有指定用户名和密码,它就会插入 anonymous(匿名用户)作为你的用户名,并发 送一个默认的密码(Internet Explorer 会发送 IEUser,Netscape Navigator 则会发送 mozilla)

路径

URL 的路径组件说明了资源位于服务器的什么地方。路径通常很像一个分级的文件系统路径。比如: http://www.joes-hardware.com:80/seasonal/index-fall.html,这个 URL 中的路径为 /seasonal/index-fall.html,很像 UNIX 文件系统中的文件系统路径,路径是服务器定位资源时所需的信息。其实这是一种简化的说法,路径并不总能为资源定位提供足够的信息,有时候服务器还需要其他的信息,可以用字符/将 HTTP URL 的路径组件划分成一些路径段(path segment)每个路径段都有自己的参数(param)组件

参数

对很多方案来说,只有简单的主机名和到达对象的路径是不够的。除了服务器正在监听的端口,以及是否能够通过用户名和密码访问资源外,很多协议都还需要更多的信息才能工作

负责解析 URL 的应用程序需要这些协议参数来访问资源,如果缺少相关的协议参数可能访问不到请求的服务。为了向应用程序提供它们所需的输入参数,以便正确地与服务器进行交互,URL 中有一个参数组件。这个组件就是 URL 中的键值对列表,由字符 ; 将各种参数分隔开来,丰富了应用程序提供访问资源的方式

比如:

  • ftp://prep.ai.mit.edu/pub/gnu;type=d,在这个例子中,有一个参数 type=d,参数名为 type,值为 d
  • 如前所述,HTTP URL 的路径组件可以分成若干路径段。每段都可以有自己的参数,http://www.joes-hardware.com/hammers;sale=false/index.html;graphics=true,这个例子就有两个路径段,hammersindex.htmlhammers 路径段有参数 sale,其值为 falseindex.html 段有参数 graphics,其值为 true

查询字符串

很多资源(如:数据库服务),都是可以通过提问题或进行查询来缩小所请求资源类型范围的。

假设 Joe 的五金商店在数据库中维护着一个未售货物的清单,并可以对清单进行查询,以判断产品是否有货,那就可以用下列 URL 来查询 Web 数据库网关,看看编号为 12731 的条目是否有货

1
http://www.joes-hardware.com/inventory-check.cgi?item=12731

这个 URL 的大部分都与我们见过的其他 URL 类似。只有问号(?)右边的内容是新出现的。这部分被称为查询(query)组件。URL 的查询组件和标识网关资源的 URL 路径组件一起被发送给网关资源。基本上可以将网关当作访问其他应用程序的访问点

除了有些不合规则的字符需要特别处理之外,对查询组件的格式没什么要求。按照常规,很多网关都希望查询字符串以一系列 key=value 的形式出现,键值对之间用字符 & 分隔:

1
http://www.joes-hardware.com/inventory-check.cgi?item=12731&color=blue

片段

有些资源类型,比如 HTML,除了资源级之外,还可以做进一步的划分

比如,对一个带有章节的大型文本文档来说,资源的 URL 会指向整个文本文档,但理想的情况是,能够指定资源中的那些章节

为了引用部分资源或资源的一个片段,URL 支持使用片段(frag)组件来表示一个资源内部的片段。比如,URL 可以指向 HTML 文档中一个特定的图片或小节片段挂在 URL 的右手边,最前面有一个字符 #

比如下面这个例子,片段 drills 引用了 Joe 的五金商店 Web 服务器上页面 /tools.html 中的一个部分。这部分的名字叫做 drills

1
http:://www.joes-hardware.com/tools.html#drills

📓HTTP 服务器通常只处理整个对象,而不是对象的片段,客户端不能将片段传送给服务器,浏览器从服务器获得了整个资源之后,会根据片段来显示你感兴趣的那部分资源

URL 快捷方式

Web 客户端可以理解并使用几种 URL 快捷方式。相对 URL 是在某资源内部指定一个资源的便捷缩略方式。很多浏览器还支持 URL 的自动扩展,也就是用户输入 URL 的一个关键(可记忆的)部分,然后由浏览器将其余部分填充起来

相对 URL

URL 有两种路径记录方式:绝对的和相对

到目前为止,我们只见过绝对 URL。绝对 URL 中包含有访问资源所需的全部信息,相对 URL 是不完整的。要从相对 URL 中获取访问资源所需的全部信息,就必须有基准,这个基准被称为基础(base)的 URL ,所有的相对 URL 都是相对于这个基础 URL 进行解析的

相对 URL 是 URL 的一种便捷缩略记法。如果你手工写过 HTML 的话,就会发现相对 URL 是多么便捷了。下面是一个嵌入了相对 URL 的 HTML 文档实例

1
2
3
4
5
6
7
8
9
10
11
<html>
<head>
<title>Joe's Tools</title>
</head>
<body>
<h1>Tools Page</h1>
<h2>Hammers</h2>
<p>Joe's Hardware Online has the largest selection of</p>
<a href="./hammers.html">hammers</a> on earth.
</body>
</html>

在这个 HTML 文档中有一个包含了 URL ./hammers.html 的超链接。这个 URL 看起 来是不完整的,但实际上是个合法的相对 URL。可以相对于它所在文档的 URL 对 其进行解释;在这个例子中,就是相对于 Joe 的五金商店 Web 服务器的资源 /tools.html

基础 URL(Base URL)

转换处理的第一步就是找到 Base URL,Base URL 是作为相对 URL 的参考点使用的,可以来自以下几个不同的地方:

  • 在资源中显式提供
    • 有些资源会显式地指定 Base URL。比如,HTML 文档中可能会包含一个定义了 Base URL 的 HTML 标记 ,通过它来转换那个 HTML 文档中的所有相对 URL
  • 封装资源的 Base URL - 如果在一个没有显式指定 Base URL 的资源中发现了一个相对 URL,可以将它所属资源的 URL 作为 Base URL

解析相对引用

要将相对 URL 转换为一个绝对 URL,下一步要做的就是将相对 URL 和基础 URL 划分成组件段,实际上,这样只是在解析 URL,但这种做法会将其划分成一个个组件,因此通常会称作分解(decomposing)URL。只要将基础和相对 URL 划分成了组件,就可以使用相关的算法将一个相对 URL 抓换成其绝对模式,之后就可以用它来引用资源了

自动扩展 URL

有些浏览器会在用户提交 URL 之后,或者在用户输入的时候尝试着自动扩展 URL。 这就为用户提供了一条捷径:用户不需要输入完整的 URL,因为浏览器会自动扩展,这些自动扩展特性有以下两种方式:主机名扩展历史扩展

主机名扩展

在主机名扩展中,只要有些小提示,浏览器通常就可以在没有帮助的情况下,将你输入的主机名扩展为完整的主机名。 比如,如果在地址栏中输入 yahoo,浏览器就会自动在主机名中插入 www..com,构建出 www.yahoo.com。如果找不到与 yahoo 匹配的站点,有些浏览器会在放弃之前尝试几种扩展形式。浏览器通过这些简单的技巧来节省你的时间,减少找不到的可能。 但是,这些主机名扩展技巧可能会为其他一些 HTTP 应用程序带来问题(比如代理)

历史扩展

浏览器用来节省用户输入 URL 时间的另一种技巧是,将以前用户访问过的 URL 历史存储起来。当你输入 URL 时,它们就可以将你输入的 URL 与历史记录中 URL 的前缀进行匹配,并提供一些完整的选项供你选择。因此,如果你输入了一个以前访问过的 URL 的开始部分,比如 http://www.joes-,浏览器就可能会建议使用 http://www.joes-hardware.com。然后你就可以选择这个地址,不用输入完整的 URL 了。

URL 中的字符处理

URL 是可移植的(portable)。它要统一地命名因特网上所有的资源,这也就意味着 要通过各种不同的协议来传送这些资源。这些协议在传输数据时都会使用不同的机制,所以,设计 URL,使其可以通过任意因特网协议安全地传输是很重要的

安全传输意味着 URL 的传输不能丢失信息。有些协议,比如传输电子邮件的简单邮件传输协议(Simple Mail Transfer Protocol,SMTP),所使用的传输方法就会剥去一些特定的字符。为了避开这些问题,URL 只能使用一些相对较小的、通用的安全字母表中的字符。

除了希望 URL 可以被所有因特网协议进行传送之外,设计者们还希望 URL 也可供人类阅读。因此,即使不可见、不可打印的字符能够穿过邮件程序,从而成为可移植的,也不能在 URL 中使用(其中最重要的一个字符就是空格

URL 还得是完整的,这就使问题变得更加复杂了。URL 的设计者们认识到有时人们可能会希望 URL 中包含除通用的安全字母表之外的二进制数据或字符。因此,需要有一种转义机制能够将不安全的字符编码为安全字符,再进行传输

URL 字符集

默认的计算机系统字符集都倾向于以英语为中心,有些 URL 中还会包含任意的二进制数据。认识到对完整性的需求之后,URL 的设计者就将转义序列集成了进去,通过转义序列,就可以用 US-ASCII 字符集的有限子集对任意字符值或数据进行编码了,这样就实现了可移植性和完整性

编码机制

为了避开安全字符集表示法带来的限制,人们设计了一种编码机制,用来在 URL 中表示各种不安全的字符。这种编码机制就是通过一种转义表示法表示不安全字符的,这种转义表示法包含一个百分号(%),后面跟着两个表示字符 ASCII 码的 十六进制数

字符ASCII 码示例
~126(0x7E)http://www.joes-hardware.com/%7Ejoe
空格32(0x20http://www.joes-hardware.com/more%20tools.html
%37(0x25http://www.joes-hardware.com/100%25satisfaction.html

字符限制

在 URL 中,有几个字符被保留起来,有着特殊的含义。有些字符不在定义的 US-ASCII 可打印字符集中。还有些字符会与某些因特网网关和协议产生混淆,因此不赞成使用

字符保留/受限原因
%保留作为编码字符的转义标志
/保留作为路径组件中分隔路径段的定界符
.保留在路径组件中使用
保留在路径组件中使用
#保留作为分段定界符使用
?保留作为查询字符串定界符使用
;保留作为参数定界符使用
:保留作为方案、用户/口令,以及主机/端口组件的定界符使用
$,+保留
@ & =在某些方案的上下文中有特殊的含义,保留
{ }| \ ^ ~ [ ] `由于各种传输 Agent 代理,比如各种网关的不安全处理,使用受限
<> "不安全;这些字符在 URL 范围之外通常是有意义的,比如在文档中对 URL 自身 进行定界(比如 http://www.joes-hardware.com),所以应该对其进行编码
0x00-0x1F,0x7F受限,这些十六进制范围内的字符都在 US-ASCII 字符集的不可打印区间内
>0x7F受限,十六进制值在此范围内的字符都不在 US-ASCII 字符集的 7 比特范围内

其他

应用程序要按照一定规范工作。客户端应用程序在向其他应用程序发送任意 URL 之前,最好把所有不安全或受限字符都进行转换。只要对所有不安全字符都进行了编码,这个 URL 就是可在各应用程序之间共享的规范形式;也就无需操心其他应用程序会被字符的任何特殊含义所迷惑了

另一种极端的做法就是应用程序对所有字符都进行编码。尽管并不建议这么做,但也没有什么强硬且严格的规则规定不能对那些安全字符进行编码;但在实际应用中,有些应用程序可能会假定不对安全字符进行编码,这么做的话可能会产生一些奇怪的破坏性行为。

📓总之,解释 URL 的应用程序必须在处理 URL 之前对其进行解码

总结

URL 是一种强有力的工具,可以用来命名所有现存对象,可以很方便地包含一些新格式。URL 还提供了一种可以在各种因特网协议间共享的统一命名机制。但 URL 并不完美。它们表示的是实际的地址,而不是准确的名字。这就意味着 URL 会告诉你资源此时处于什么位置。它会为你提供特定端口上特定服务器的名字,告诉你在何处可以找到这个资源

😣这种方案的缺点在于如果资源被移走了, URL 也就不再有效了。那时,它就无法对对象进行定位了

在可预见的未来,因特网资源仍然会以 URL 来命名。它们是 Web 能够成功非常重要的部分。其他命名方案想要取代 URL 还要一段时间。但是,URL 由于有其局限型,可能会出现新的标准(可能是 URN),对这种标准进行部署会解决其中的某些问题