我所认识的 HTTP
原文链接 http://inskyline.com/book/2017/06/09/a-book-kown_http.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
在 1989 年三月的一天,CERN(欧洲核子研究组织)的伯纳斯李(Tim BernerLess)博士提出一种让远隔两地的研究者们共享知识的设想。将共享的资料文档相互关联形成超文本(Hyper-Text),文档如何在网络上传输,以及到了另一端如何识别,当时有一个共识这些事情站需要站在另一个巨人 TCP/IP 肩上,形成了一项协议起名为HTTP(超文本传输协议)。
李博士提出设想到 1990 年 11 月第一个网站上线,发展到 1996 年 5 月 HTTP 作为标准公布,并命名为 HTTP/1.0。1997年1月公布了HTTP/1.1,HTTP/1.1还是现在的主流的版本。
HTTP 是建立在 TCP/IP 之上。TCP/IP协议族按照层次分为:应用层、传输层、网络层和数据链路层。应用层决定了向用户提供应用服务时通信的活动,并预存了各类通用的应用服务。比如说 FTP、DNS等,太好了 HTTP 协议就应该在这里。
HTTP 协议在应用层产生数据包(HTTP报文),然后交给 IP协议 把各种数据传给对方。IP 在传输的过程中,不一定可靠,这个时间 TCP 老兄出现了,把传输的数据分割,并采用三次握手的方式准确可靠的传达到对方。访问一个网页一般是用域名,域名怎么和 IP 关联起来呢?这个事情由 HTTP 的另一个兄弟 DNS 负责。
李博士的设想这样变为现实,在 TCP/IP 协议之上的 HTTP 本身,不庞大,但很有内涵,特点十分鲜明。
- HTTP 协议用于客户端和服务器端之间的通信。这条通信线路上必须有一个客户端和一个服务器,通过请求和响应的交换达成通信。
- HTTP是一种不保存状态的协议。
众所周知,HTTP是通过 URI 定位互联网的资源。URI 确定后,访问服务器,需要告知服务器客户端意图。如何告知意图呢?HTTP有它的方法,HTTP 方法分别是:
- GET 获取资源
- POST 传输实体
- PUT 传输文件
- HEAD 获取报文的头部
- DELETE 删除文件
- OPTIONS询问自持的方法
- TRACE 追踪路径,这个方法由于容易引起XST 攻击,已经很少用了
- CONNECT 要求用隧道协议链接代理。主要使用有 SSL 和 TLS
由于 HTTP 是无状态的,导致每次 HTTP 通信都要断开一次 TCP 链接。当年传输的内容比较少没有问题,随着发展,传输的内容增多,这种方式为通信造成了很大的开销。HTTP/1.1 提出了持久化链接(HTTP keep-live)。持久化链接减少了 TCP 链接的重复建立和断开造成的额外的开销,减轻了服务器的负载。
为了达到持久化,又引入了两个技术,管线化和 Cookie 。
管线化之前发送请求后需要等待并接受到响应后,才能发送下一个请求。管线化出现后不用等待响应就可以直接发送下一个请求。
持久化链接时服务端如何知道某个客户端呢?出现 Cookie 做状态管理。Cookie 根据从服务器发送响应报文内的Set-Cookie 的字段信息,通知客户端保存 Cookie。当下次客户端再往服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值发送到服务器。服务器发现客户端发送 Cookie 确定是那个客户端发送过来的请求。
请求和响应的内容是如何组织的呢?
用于 HTTP 协议交互的信息称为 HTTP 报文。请求端的叫请求报文,服务器端的叫响应报文。HTTP 报文本身是由多行(用CR+LF作为换行符)数据构成字符串文本组成。报文又分为报文首部和报文主体两块。
报文中包含请求行包含了请求的方法,请求的 URI 和 HTTP 版本。
状态行包含响应结果的状态码
首部字段包含请求和响应的各种条件和属性的各类首部。
HTTP 首部字段是构成 HTTP 报文的重要要素。通过以 Key 和 Value 形式构成。
通常有 4 种首部:
- 通用首部 请求报文和响应报文都会使用到。
- 请求首部字段 从客户端向服务端发送请求时使用的首部。
- 响应首部字段 从服务器端向客户端返回报文时使用的首部。
- 实体首部字段 针对请求报文和响应报文的实体部分使用的字段。
这是请求百度百科产生的报文首部(内容并不全):
1. 1. Request URL:http://baike.baidu.com/
2. Request Method:GET
3. Status Code 200 OK
4. Remote Address:127.0.0.1:9742
5. Referrer Policy:unsafe-url
2. Response Headersview source
3. 1. Connection:keep-alive
2. Content-Encoding:deflate
3. Content-Type:text/html
4. Date:Mon, 29 May 2017 16:54:28 GMT
5. Server:Apache
6. Tracecode:32681390030198060554053000
7. Transfer-Encoding:chunked
8. Vary:accept-encoding
4. Request Headersview source
5. 1. Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
2. Accept-Encoding:gzip, deflate, sdch
3. Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2
4. Cache-Control:no-cache
5. Connection:keep-alive
HTTP/1.1 规范定义了 47 种首部字段,大名鼎鼎的 Cookie
、Set-Cookie
还不在其中。可见首部字段的重要和庞多样化。
内容是怎么的传输呢?
HTTP 传输数据时通过编码提升效率。HTTP协议中有一种被称为内容编码的功能,将数据编码,并保持实体原样进行压缩。常用的内容编码有 gzip、compress、deflate、identity 等。传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。这种分块功能称为分块传输编码(Chunked Transfer Coding)。
传输的不同类型的数据,通过 MIME 描述数据类型,需要在 HTTP 报文的首部字段加上 Content-type。
传输数据到服务器后,服务器有时间并不能直接知道响应什么最合适。这个时间就用到 HTTP 协议的内容协商机制。客户端和服务器就响应的资源进行交涉,然后提供给客户端最为合适的资源。
内容协商技术有 3 种:
- 服务器驱动协商。服务器以请求的首部字段参考,服务端自动处理。
- 客户端驱动协商。从浏览器显示可选择列表手动选择。比如浏览器对某个网站提示用英文版之类。
- 透明协商。服务器和客户端结合判定的一种方式。
客户端发送数据给服务器端,服务器端需要响应到客户端。如何确定服务器对接受到客户端信息处理是否正常呢?这里引入了HTTP状态码。
状态码告知从服务端返回的请求结果。通过状态码,用户知道服务器正常处理了请求还是有其他意外。状态码以 3 位数字组成。数字中第一位指定响应类型,后两位没有分类。
响应类型有 5 类:
类别 | 原因短语 | |
---|---|---|
1XX | Informational(信息性状态码) | 接受到的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
据统计状态码的数量多达 60 多种,实际经常使用的大概 14 种。分别为 200、204(No Content)、206(Partial Content)、301、302、303(See other)、304、307、400、401、403、404、500、503。
目前认识了 HTTP数据包、以及如何传输。同时发现 HTTP 通信是使用明文,而且不验证通信方的身份。不过这事在 1994 年网景开发浏览器时已经意识到,网景在其浏览器中内置对数据进行加密和解密操作,并返回网络上传送回的结果。这个加密层称为安全套接(SSL) ,以 HTTP 应用层的子层出现,最初 HTTP 和 SSL 一起使用的,在SSL 逐渐演变到 TLS 时,最新的 HTTPS 在 2000 年五月公布的RFC 2818 正式确定。
HTTPS=HTTP+加密+认证+完整性保护
有了 HTTPS 后安全性的问题得到一定的解决。如果一个网站,某些内容只要让特定人群访问,该如何做呢?
HTTP/1.1 确定了4 种重要的认证方式
- BASIC 认证
- DIGEST 认证
- SSL 客户端认证
- FormBase 认证(基于表单的认证)
这些问题解决后,似乎 HTTP 协议保证我们在互联网上自由的冲浪了。97 年的颁布的 HTTP/1.1 的确在这么多年基本满足我们的需求。随着 Web 技术的进一步发展,HTTP/1.1 在好多方面捉襟见肘。这期间出现好多解决方案,比如 Google 的 SPDY。终于等到2015年出现了 HTTP/2 。
接下来,我去认识 HTTP/2 去了!