《HTTP权威指南》学习笔记(1)-HTTP概述和URL

引言

HTTP协议,一个熟悉又陌生的应用协议。熟悉的是它在各种计算机网络教材中必然会被提及的应用层协议,稍微有点计算机知识的人基本上都会听过这个协议。它是互联网的基础,可以这么说,没有HTTP协议,就没有当前互联网的蓬勃发展。然而,笔者对它又是陌生的。因为虽然参与开发了不少Web应用,但很少直接与HTTP协议直接打交道,因为Web容器隐藏了很多HTTP协议的细节(譬如:请求协议头的解析,响应报文的生成),使得上层开发不用关心HTTP即可以开发出可用的Web应用。不应该仅仅满足可用,还应该让应用更加高效,这促使我不得不去研究HTTP协议。私以为,如果想进一步提升自己的技术能力,必须要深入到协议层级别,一些平时感觉到莫名其妙的问题就可以迎刃而解。

最近阅读了《HTTP权威指南》一书,本文包含书中的核心要点、个人延伸以及个人操作实践。由于本书是2009年出版,距现在已经有6年之久,期间,HTTP协议本身也不断地发展。所以,一些老旧的知识点将不会出现在本文中。希望通过不断阅读和实践,并且记录下来,能够加深对HTTP协议本身的理解!

HTTP协议概述

本节介绍一些HTTP的基础知识,先对HTTP有一个宏观上的了解。

HTTP协议是什么

平常老看到TCP/IP协议、FTP协议,XX协议……不禁要问,到底什么是协议?查阅了百度百科,上面是这么定义的:

基本解释:共同计议;协商
法律范畴:协议是指两个或两个以上实体为了开展某项活动,经过协商后双方达成的一致意见。

感觉上面的解释有些简单和抽象,但是从中不难看出协议有下面两个要点:

  1. 两个及两个以上参与者。也就是说,如果只有一方参与,根本就不会涉及到协议。
  2. 协商一致。也就是说,所有参与方都必须同意并且遵守,才能使得活动能正常运行下去。

上面讲的一般意义上的协议,在计算机领域中,我们讲的协议一般是指通信协议,它仍然遵循上面的要点。首先,通信必然涉及到多方参与;其次,如果有一方不遵守协议,则根本没法进行有效通信。

下面来看看啥是HTTP协议,百度百科是这么说的:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。

HTTP协议的特点

下面从这篇博客中转过来的HTTP协议的特点,这篇文章对HTTP做了很全面的介绍,值得一读。

  1. 支持客户/服务器模式。支持基本认证和安全认证。
  2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  3. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  4. HTTP 0.9和1.0使用非持续连接(无连接性):限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。HTTP 1.1使用持续连接:不必为每个web对象创建一个新的连接,一个连接可以传送多个对象。
  5. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大

特别直接说明的是HTTP的连接性。在我以前的认识里,HTTP最重要的特性是无连接性和无状态性。所谓无连接性,是指每一次请求都使用新的连接,请求完毕后连接关闭。这样做最大的好处时,最大程度上减少空闲连接占用服务端资源,这在系统资源比较昂贵、页面比较简单、仅传输静态页面的年代确实是非常合理的。但是,随着电商、视频等富媒体Web应用的兴起,HTTP的无连接性制约了系统的性能。一个Web应用动辄上百张图片,每一张图片都要占用一个网络连接。要知道,每新建一个连接都需要在TCP协议层进行“三次握手”,效率非常低下。随着在HTTP v1.1版本中默认采用Keep-Alive,多个请求可以使用同一个连接,HTTP的无连接性描述已经变得不准确了。

版本变化

  • HTTP/0.9 已过时。只接受 GET 一种请求方法,没有在通讯中指定版本号,且不支持请求头。由于该版本不支持 POST 方法,所以客户端无法向服务器传递太多信息。
  • HTTP/1.0 这是第一个在通讯中指定版本号的HTTP 协议版本,至今仍被广泛采用,特别是在代理服务器中。
  • HTTP/1.1 当前版本。持久连接被默认采用,并能很好地配合代理服务器工作。还支持以管道方式同时发送多个请求,以便降低线路负载,提高传输速度。

URL与资源

什么是URL

URL(Uniform Resource Location, 统一资源定位符)是Internet上的所有资源的标准化名称。可以把Internet看做一个巨大的正在扩张的城市,里面充满了各种可看的东西,可做的事情。我们需要为这个城市里面的所有景点和服务起一个名字,所有的名字必须在符合统一的标准,这样才能使得我们方便地使用这座城市的宝藏。URL就是其中一类重要的资源命名方式。URL指向每一条电子信息,告诉你它位于何处,如何与之进行交互。URL必须是唯一的,也就是说,一个URL只能对应唯一的资源。

URI、URL和URN

说起URL,就必然要提URI和URN。那么它们之间到底有什么联系和区别呢?首先来看看URI和URN是什么。

  • URI:即Uniform Resource Identifier,统一资源标识符。它是一个通用的概念,理论上,能保证资源全局唯一性的标识符都可以叫做URI;
  • URN:即Uniform Resource Name,统一资源名称。这样的资源名是与资源具体的位置无关的。

URI、URL、URN是相互关联的。URL和URN都是URI的子集,按照集合论的观点,它们之间的关系见下图。

URL URI URN的关系图

也就说,任何的URL都可以是URI,反之不然。URL是与资源所处的位置密切相关的,如果资源挪动位置,则必然导致URL跟着一起变化。想象一下,如果资源换了位置(虽然这极少发生),则原来开发的软件就会失效。URN主要就是为了解决这个问题而提出来的。它通过给资源命名而不是定位来唯一地确定资源。

假定现在要给我起个独一无二的名称,我可以自己命名为此时我所处的地理位置,假设是(东经36度,北纬36度)。好了,现在请叫我(东经36度,北纬36度),通过地图肯定可以找到我。然而,我并不是时时刻刻都呆着这里的,因为我是个活人。当我移动位置之后,通过原来的位置定位到的已然不是我了,这就很麻烦了。如果用我的姓名来找我(假设是独一无二的),则无论何时何地找到的都是我了。

目前来说,URN貌似还没能到实用阶段,看上去用处也不大。一则资源位置一般不会发生变动;二则URL已经完全普及,为啥要抛弃已经用得溜溜的东西呢?!至少目前还没有理由这么干。所以,在《HTTP权威指南》一书中,并没有将URI和URL区分开来,所有的URI都可以看做是URL。

URL的完整语法

在Web应用中,URL通常是由3各部分构成,以URL地址http://www.joes.com/seanonal/index.html为例来进行说明。

  • 第一部分(http)是方案(schema),可以告知客户端怎样访问资源。
  • 第二部分(www.joes.com)是服务器的位置,告知客户端资源位于何处。
  • 第三部分(/seanonal/index.html)是资源路径。

上面的URL地址只是众多格式的URL地址中的一种,实际上,URL还可以通过HTTP以外的其他协议来进行访问。比如个人E-mail账户:

1
mailto:xialei199023@163.com

或者是通过FTP协议获取文件:

1
ftp://ftp.xxx.com/file.xls

咋一看,这些URL的格式都不太一样,这是不是意味着每种不同的URL方案会有完全不同的语法呢?其实不然。大多数URL语法都建立在9个部分构成的通用格式上:

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

每一部分的的意义如下:

  • schema:获取资源时使用何种协议
  • user:访问资源时需要的用户名
  • password:访问资源时与用户名配套的密码
  • host:资源所在的服务器地址
  • port:服务器所监听的端口
  • path:服务器上的本地资源路径,用/分隔
  • params:指定输入参数,用key/value表示
  • query:资源查询参数
  • frag:资源内部的片段名字

URL通常会由其中的某些部分组合而成,下面是一些URL典型示例:

1
2
3
4
5
6
http://www.joes.com/seanonal/index.html
file:///D:/relativeUrl.html
ftp://username:password@ftp.xxx.com/file.xls
http://www.joes.com/seanonal/index.html;type=d
http://www.joes.com/seanonal/goods.html?item=45454
http://www.joes.com/seanonal/goods.html?item=45454#name

相对URL

绝对URL和相对URL是URL的两种不同的表现形式,前面所有的URL示例都是绝对URL,绝对URL包含访问资源所需的全部资源。下面是一个简单的HTML页面代码,其中的page1就是一个包含相对URL的链接。

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>page2</title>
</head>
<body>
<a href="./page1.html">page1</a>
</body>
</html>

相对URL是不完整的,要获取资源的全部信息,还要依赖称为基础(base)的URL。基础URL通常来自以下地方:

第一,在资源中显示提供。在HTML文档中,可以由<base>标签定义一个基础URL。下面的代码定义了<base href=”http://www.demo.com/base/“ ></base> ,于是,page2实际的绝对地址就是:http://www.demo.com/base/page2.html

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>page1</title>
<base href="www.demo.com/base/"></base>
</head>
<body>
<a href="./page2.html">page2</a>
</body>
</html>

第二,所属资源的URL作为基础URL。还是以上面的代码为例。假定page1.html的绝对URL是http://www.demo.com/page1.html,那么page1.html属于http://www.demo.com/资源下的。直接用这个地址作为基础URL,则page2的绝对URL是:http://www.demo.com/page2.html

第三,没有基础URL。注:这里没有看懂,先列在这里……

URL编码

合格的URL应该满足下面的要求:

  • 可移植性:作为统一的命名,应该要能够通过不同的协议来传送资源。不同的协议可能会有特定的保留字符,在不同的协议中传输时,不应该因为这些特殊字符而丢失信息。
  • 可读性:不可见的、不可打印的(比如空格)字符不应该出现在URL中。
  • 完整性:可能需要通用字符外的二进制数据或字符,因此需要一种转义机制,将不安全的字符编码为安全字符。

从历史来看,计算机应用程序都是用US-ASCII字符集^footnote。由于其历史悠久,所以可移植性很好。但是它不支持数百种非罗马语言中的字符。这就需要一套转义编码机制,用US-ASCII字符集来对任意字符进行编码。目前设计的转义表示法是用一个“%”,后面跟着两个表示ASCII码的十六进制数。下面是一些编码示例:

字符 ASCII码 示例
~ 126(0x7E) http://www.baidu.com/%7E(http://www.baidu.com/~)
空格 32(0x20) http://www.baidu.com/?query=http%20url(http://www.baidu.com/?query=http url)
% 37(0x25) http://www.baidu.com/?query=1%255(http://www.baidu.com/?query=1%5)

总结

本文是《HTTP权威指南》学习笔记的第一篇,介绍一些HTTP中的基本概念和概述。重点介绍了URL(统一资源定位符)这一种最重要的Web资源命名方式,将其与URI、URN这类经常混淆的概念进行的比较。概要说明了URL的语法格式、相对URL和URL编码。首先对HTTP有一个整体上的认识,接下来要写的是HTTP中的重要细节内容,与日常的开发密切相关。