2.2 URL 的语法
URL 提供了一种定位因特网上任意资源的手段,但这些资源是可以通过各种不同的方案(比如 HTTP、FTP、SMTP)来访问的,因此 URL 语法会随方案的不同而有所不同。
这是不是意味着每种不同的 URL 方案都会有完全不同的语法呢?实际上,不是的。大部分 URL 都遵循通用的 URL 语法,而且不同 URL 方案的风格和语法都有不少重叠。
大多数 URL 方案的 URL 语法都建立在这个由 9 部分构成的通用格式上:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
几乎没有哪个 URL 中包含了所有这些组件。URL 最重要的 3 个部分是方案(scheme)、主机(host)和路径(path)。表 2-1 对各种组件进行了总结。
表2-1 通用URL组件
组 件 | 描 述 | 默 认 值 |
---|---|---|
方案 | 访问服务器以获取资源时要使用哪种协议 | 无 |
用户 | 某些方案访问资源时需要的用户名 | 匿名 |
密码 | 用户名后面可能要包含的密码,中间由冒号(:)分隔 | <E-mail地址> |
主机 | 资源宿主服务器的主机名或点分IP地址 | 无 |
端口 | 资源宿主服务器正在监听的端口号。很多方案都有默认端口号(HTTP的默认端口号为80) | 每个方案特有 |
路径 | 服务器上资源的本地名,由一个斜杠(/)将其与前面的URL组件分隔开来。路径组件的语法是与服务器和方案有关的(本章稍后会讲到URL路径可以分为若干个段,每段都可以有其特有的组件。) | 无 |
参数 | 某些方案会用这个组件来指定输入参数。参数为名/值对。URL中可以包含多个参数字段,它们相互之间以及与路径的其余部分之间用分号(;)分隔 | 无 |
查询 | 某些方案会用这个组件传递参数以激活应用程序(比如数据库、公告板、搜索引擎以及其他因特网网关)。查询组件的内容没有通用格式。用字符“?”将其与URL的其余部分分隔开来 | 无 |
片段 | 一小片或一部分资源的名字。引用对象时,不会将frag字段传送给服务器;这个字段是在客户端内部使用的。通过字符“#”将其与URL的其余部分分隔开来 | 无 |
比如,我们来看看URL:http://www.joes-hardware.com:80/index.html,其方案是 http,主机为 www.joes-hardware.com,端口是 80,路径为 /index.html。
2.2.1 方案——使用什么协议
方案实际上是规定如何访问指定资源的主要标识符,它会告诉负责解析 URL 的应用程序应该使用什么协议。在我们这个简单的 HTTP URL 中所使用的方案就是 http。
方案组件必须以一个字母符号开始,由第一个“:”符号将其与 URL 的其余部分分隔开来。方案名是大小写无关的,因此 URL“http://www.joes-hardware.com” 和 “HTTP://www.joes-hardware.com”是等价的。
2.2.2 主机与端口
要想在因特网上找到资源,应用程序要知道是哪台机器装载了资源,以及在那台机器的什么地方可以找到能对目标资源进行访问的服务器。URL 的主机和端口组件提 供了这两组信息。
主机组件标识了因特网上能够访问资源的宿主机器。可以用上述主机名(www.joeshardware.com),或者 IP 地址来表示主机名。比如,下面两个 URL 就指向同一个资源——第一个 URL 是通过主机名,第二个是通过 IP 地址指向服务器的:
http://www.joes-hardware.com:80/index.html
http://161.58.228.45:80/index.html
端口组件标识了服务器正在监听的网络端口。对下层使用了 TCP 协议的 HTTP 来说,默认端口号为 80。
2.2.3 用户名和密码
更有趣的组件是用户和密码组件。很多服务器都要求输入用户名和密码才会允许用户访问数据。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,但用户没有提供,它通常会插入一个默认的用户名和密码。比如,如果向浏览器提供一个 FTP URL,但没有指定用户名和密码,它就会插入 anonymous(匿名用户)作为你的用户名,并发送一个默认的密码(Internet Explorer 会发送 IEUser,Netscape Navigator 则会发送 mozilla)。
第二个例子显示了一个指定为 anonymous 的用户名。这个用户名与主机组件组合在一起,看起来就像 E-mail 地址一样。字符“@”将用户和密码组件与 URL 的其余部分分隔开来。
在第三个例子中,指定了用户名(anonymous)和密码(my_passwd),两者之间由字符“:”分隔。
2.2.4 路径
URL 的路径组件说明了资源位于服务器的什么地方。路径通常很像一个分级的文件系统路径。比如:
http://www.joes-hardware.com:80/seasonal/index-fall.html
这个 URL 中的路径为 /seasonal/index-fall.html,很像 UNIX 文件系统中的文件系统路径。路径是服务器定位资源时所需的信息。1可以用字符“/”将 HTTP URL 的路径组件划分成一些路径段(path segment)(还是与 UNIX 文件系统中的文件路径类似)。每个路径段都有自己的参数(param)组件。
1 这是一种简化的说法。在 18.2 节我们会看到,路径并不总能为资源定位提供足够的信息。有时服务器还需要其他的信息。
2.2.5 参数
对很多方案来说,只有简单的主机名和到达对象的路径是不够的。除了服务器正在监听的端口,以及是否能够通过用户名和密码访问资源外,很多协议都还需要更多的信息才能工作。
负责解析 URL 的应用程序需要这些协议参数来访问资源。否则,另一端的服务器可能就不会为请求提供服务,或者更糟糕的是,提供错误的服务。比如,像 FTP 这样的协议,有两种传输模式,二进制和文本形式。你肯定不希望以文本形式来传送二进制图片,这样的话,二进制图片可能会变得一团糟。
为了向应用程序提供它们所需的输入参数,以便正确地与服务器进行交互,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
这个例子就有两个路径段,hammers 和 index.html。hammers 路径段有参数 sale,其值为 false。index.html 段有参数 graphics,其值为 true。
2.2.6 查询字符串
很多资源,比如数据库服务,都是可以通过提问题或进行查询来缩小所请求资源类型范围的。
假设 Joe 的五金商店在数据库中维护着一个未售货物的清单,并可以对清单进行查询,以判断产品是否有货,那就可以用下列 URL 来查询 Web 数据库网关,看看编号为 12731 的条目是否有货:
http://www.joes-hardware.com/inventory-check.cgi?item=12731
这个 URL 的大部分都与我们见过的其他 URL 类似。只有问号(?)右边的内容是新出现的。这部分被称为查询(query)组件。URL 的查询组件和标识网关资源的 URL 路径组件一起被发送给网关资源。基本上可以将网关当作访问其他应用程序的访问点(第 8 章会对网关进行详细的讨论)。
图 2-2 中有一个作为 Joe 的五金商店清单查询应用程序的网关的服务器,在这个例子中向此服务器发送了一个查询组件。查询的目的是检查清单中是否有尺寸为 large、颜色为 blue 的条目 12731。
图 2-2 发送给网关应用程序的 URL 查询组件
在本章稍后会看到,除了有些不合规则的字符需要特别处理之外,对查询组件的格式没什么要求。按照常规,很多网关都希望查询字符串以一系列“名 / 值”对的形式出现,名值对之间用字符“&”分隔:
http://www.joes-hardware.com/inventory-check.cgi?item=12731&color=blue
在这个例子中,查询组件有两个名 / 值对:item=12731 和 color=blue。
2.2.7 片段
有些资源类型,比如 HTML,除了资源级之外,还可以做进一步的划分。比如,对一个带有章节的大型文本文档来说,资源的 URL 会指向整个文本文档,但理想的情况是,能够指定资源中的那些章节。
为了引用部分资源或资源的一个片段,URL 支持使用片段(frag)组件来表示一个资源内部的片段。比如,URL 可以指向 HTML 文档中一个特定的图片或小节。
片段挂在 URL 的右手边,最前面有一个字符“#”。比如:
http://www.joes-hardware.com/tools.html#drills
在这个例子中,片段 drills 引用了 Joe 的五金商店 Web 服务器上页面 /tools.html 中的一个部分。这部分的名字叫做 drills。
HTTP 服务器通常只处理整个对象,2 而不是对象的片段,客户端不能将片段传送给服务器(参见图 2-3)。浏览器从服务器获得了整个资源之后,会根据片段来显示你感兴趣的那部分资源。
2 在 15.9 节会看到 HTTP Agent 代理可能会请求某个字节范围内的对象,但在 URL 片段的上下文中,服务器会发送整个对象,由 Agent 代理将片段标识符应用于资源。
图 2-3 服务器处理的是整个对象,因此 URL 片段仅由客户端使用