超文本传输协议(HTTP,HyperText Transfer Protocol)是一个简单的请求-响应协议,它通常运行在TCP之上。
连接
浏览器与服务器联系最常用的方法是与服务器上的端口80建立一个TCP连接,虽然这个过程不是正式要求的。使用TCP的意义在于浏览器和服务器都不需要担心如何处理长消息、可靠性或拥塞控制。所有这些事情都由TCP实现负责处理。
在Web早期HTTP 1.0中,连接被建立起来以后浏览器只发送一个请求,之后一个响应消息被发回来,再然后TCP连接就被释放了。那时,整个Web页面通常只包含HTML文本,因此这种方法足够用了。很快,Web页面发展成还含有大量的嵌入式内容链接,例如图表等,建立一个单独的TCP连接来传输每个图标的操作方式代价太昂贵。
HTTP 1.1支持持续连接(persistent connection)。有了这种连接,就有可能建立一个TCP连接,在其上发送一个请求并得到一个响应,然后再发送额外的请求并得到额外的响应。这种策略也称为连接重用(connection reuse)。通过把TCP连接的建立、启动和释放等开销分摊到多个请求上,相对于每个请求的TCP开销就被大大地降低了。而且,还可以发送流水线请求,也就是说在请求1的响应回来之前发送请求2。
然而,持续连接不是免费的。一个新的问题出现了,什么时候关闭连接?一个到服务器的连接在页面加载时应该保持开放,然后呢?对用户来说有个很好的机会,他可以点击一个链接从服务器请求另一个页面。如果连接保持打开状态,那么下一个请求被立即发送出去。不过,谁也不能保证任意时间后客户将向服务器发出另一个请求。实际上,客户机和服务器通常将持续连接保持打开状态,直到它们已经闲置一小段时间(例如60秒),或者它们已经打开了大量的连接必须要关闭一些。
HTTP报文
HTTP报文结构由报文首部,空行,报文主体三部分组成
报文首部 |
---|
空行 |
报文主体 |
HTTP首部字段通常分为4种类型:通用首部,请求首部,响应首部,实体首部
HTTP请求报文:一个HTTP请求报文由请求行(request line)、请求头部(request header)、空行和请求数据4个部分构成。
请求行数据格式由三个部分组成:请求方法、URI、HTTP协议版本,他们之间用空格分隔
GET /index.html HTTP/1.1
HTTP响应报文:一个HTTP响应报文由状态行(HTTP版本、状态码)、响应头部、空行和响应体4个部分构成。
状态行主要给出响应HTTP协议的版本号、响应返回状态码、响应描述,同样是单行显示
HTTP/1.1 200 OK
方法
每个HTTP请求由一行或多行ASCII文本组成,其中第一行的第一个词是被请求的方法名字。方法名区分大小写。因此GET是合法的方法而get不是。下表列出了内置的方法。
方法 | 描述 |
---|---|
GET | 请求获取指定资源 |
HEAD | 读取指定资源的响应头 |
POST | 向指定资源提交数据 |
PUT | 请求服务器存储一个资源 |
DELETE | 请求服务器删除指定资源 |
TRACE | 回显服务器收到的请求,主要用于测试或诊断 |
CONNECT | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 |
OPTIONS | 返回服务器支持的HTTP请求方法 |
每个请求都会得到一个响应,每个响应消息由一个状态行及可能的附加信息(例如全部或部分Web页面)组成。状态行包括一个3位数字的状态码,该状态码指明了这个请求是否被满足;如果没有满足,那么原因是什么。第一个数字把响应分成5大组,如下图所示:
代码 | 含义 | 例子 |
---|---|---|
1xx | 信息 | 100=服务器同意处理客户请求 |
2xx | 成功 | 200=请求成功;204=没有内容 |
3xx | 重定向 | 301=移动页面;304=缓存的页面仍然有效 |
4xx | 客户错误 | 403=禁止页面;404=页面没找到 |
5xx | 服务器错误 | 500=服务器内部错误;503=稍后再试 |
1xx码实际上很少被使用。
2xx码意味着这个请求被成功地处理,并且返回了相应的内容(如果有的话)。
3xx码告诉客户应该检查其他地方:使用另一个不同的URL,或者在它自己的缓存中查找。
4xx码意味着由于客户错误而导致请求失败,比如无效请求或者不存在的页面。
5xx错误码意味着服务器自身内部出现问题,有可能是服务器代码中有错误,也可能是临时负载过重。
消息头
请求行(例如GET方法的行)后面可能还有额外的行,其中包含了更多的信息。它们同称为请求头(request header)。响应消息也有响应头(response header)。有些头可以用在两个方向上。
头 | 类型 | 内容 |
---|---|---|
User-Agent | 请求 | 有关浏览器及其平台的信息 |
Accept | 请求 | 客户可处理的页面类型 |
Accept-Charset | 请求 | 客户可接受的字符集 |
Accept-Encoding | 请求 | 客户可处理的页面编码 |
Accept-Language | 请求 | 客户可处理的自然语言 |
If-Modified-Since | 请求 | 检查新鲜度的时间和日期 |
If-None-Match | 请求 | 先前为检查新鲜度而发送的标签 |
Host | 请求 | 服务器的DNS名字 |
Authorization | 请求 | 列出客户的信任凭据 |
Referer | 请求 | 发出请求的先前URL |
Cookie | 请求 | 给服务器发回Cookie的先前URL |
Set-Cookie | 响应 | 客户存储的Cookie |
Server | 响应 | 有关服务器的信息 |
Content-Encoding | 响应 | 内容如何编码(比如,gzip) |
Content-Language | 响应 | 页面使用的自然语言 |
Content-Length | 响应 | 页面以字节计的长度 |
Content-Type | 响应 | 页面的MIME类型 |
Content-Range | 响应 | 标识了页面内容的一部分 |
Last-Modified | 响应 | 页面最后修改的时间和日期 |
Expires | 响应 | 页面不再有效的时间和日期 |
Location | 响应 | 告诉客户向谁发送请求 |
Accept-Ranges | 响应 | 指出服务器能接受的请求的字节范围 |
Date | 请求/响应 | 发送消息的日期和时间 |
Range | 请求/响应 | 标识一个页面的一部分 |
Cache-Control | 请求/响应 | 指示如何处理缓存 |
ETag | 请求/响应 | 页面内容的标签 |
Upgrade | 请求/响应 | 发送方希望切换的协议 |
——摘自《计算机网络》第5版