文章目录
一、HTTP概述
HTTP(HyperText Transfer Protocol,超文本传输协议)基于TCP协议的应用层协议,最初设计目的就是为了实现简单的信息发布与文本传输,既然是协议就要求通信双方共同遵守一定的规则,其设计理念采用简洁清晰的请求、响应业务模型,客户端按双方共同遵守的约定语法向服务器发出资源请求,服务器识别解析客户端的请求,并构造响应报文将客户端请求的资源发送给客户端,如此一来一回的过招就完成了一个回合,我们称为完成了一条HTTP事务,这就是HTTP协议简单而高效。
1.HTTP架构
HTTP算是典型的C/S架构模型,最初HTTP的客户端程序就是浏览器,服务器端存储着客户端浏览器能够解析并渲染的特殊结构文档资源(我们称为HTML文档),更重要的是服务器端还时刻运行着能够接收并识别客户端的请求的WEB服务,并能够将客户端请求的文档资源封装在HTTP协议内交付给客户端。最初客户端浏览器程序是Netscape公司发布的Navigator浏览器,是商业化的浏览器,虽然是收费的但也积累了一定数据量的客户。1995年8月微软公司发布的Windwos95视窗系统中集成了免费的浏览器Internet Explore 1.0,两家公司经过几年的市场角逐,最后微软公司的IE浏览器胜出,几年时间里两家公司都为HTTP协议普及做了出很大的贡献,尤其是随着微软公司的视窗系统占领了大量PC市场走进家庭用户,一定程度上促进了HTTP协议业务的普及。
2.HTTP协议现状
时至今天移动互联网的迅猛发展,HTTP客户端已不是单纯的浏览器,各种手机APP软件、企业中的各种业务平台基本上都采了HTTP协议,只不过HTTP协议采用的是明文传输,通过嗅探抓包、劫持技术可以很轻松的获取其传输的数据存在安全问题,为此近两年业内基本上都开始了全站HTTPS协议的部署,即基于TLS(传输层安全)的HTTP协议,本质上还是HTTP通信,只不是引入传输层加密技术,逻辑上可以理解为:HTTP协议由TLS隧道来承载,一定程度上提升了数据传输过程中的安全性,但请记住没有绝对的安全,同样存在中间人攻击的安全问题。
3.HTTP版本
互联网发展到今天,HTTP协议也经历了多个版本的更替,从最初的HTTP0.9到当前正在逐步走向主流的HTTP2.0,HTTP协议的功能和特性在不断的完善,很多功能特性都是基于原有技术的升级,所以想学好HTTP就有必要了解一下HTTP协议各版本的特性。
-
HTTP0.9
1991年发布HTTP9.0作为HTTP协议的雏形版本,功能简陋,只有一个GET方法,服务器只能回应HTML格式字符串,不能回应别的格式,也就是说只能进行文本封装,不支持图片、声音、视频。 -
HTTP1.0 1996年5月发布 HTTP1.0
RFC参考文献:https://www.ietf.org/rfc/rfc1945.txt
新功能特性:首次引用了MIME(多用途互联网邮件扩展类型)使网页变得丰富多彩,同时支持Cache功能(节省了带宽资源),HTTP方法方面引入:POST、HEAD。- MIME(多用途互联网邮件扩展类型):RFC 2045-2049*
MIME的数据结构由两级标识构成,格式为:text/xml image/jpeg audio/mp3
一级标识: 声明信息类型,如:文本、图像、音频、视频以及其他应用程序专用的数据
二级标识: 说明具体的数据格式,在操作系统中每种数据格式都有特定的文件扩展名,操作系统可以基于文件扩展名来判断应该用哪种应用程序处理文件。
MIME类型处理:
windows基于扩展名来识别用哪种程序打开文件,而linux则不需要扩展名,直接读文件头部信息中的MIME即可判断应该用哪种程序来处理文件(linux中可以用file -i查看文件的mime类型)。
MIME在HTTP1.0中的实现
HTTP1.0 通过在HTTP头部分添加Accept、Content-Type字段一对字段来支持MIME功能。客户端在发起HTTP请求的报文头部增加Accept字段来声明客户端支持的mime类型,服务器端在HTTP响应报文头部增加Content-Type说明该资源是哪种MIME类型。如下图所示: - 通信机制:
每个TCP连接只能完成一个HTTP事务,即:一个TCP会话只能发送一个请求,发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。 - HTTP新方法:引入了POST和HEAD方法
POST: 允许客户端以提交表单的方式向服务器提交数据,该特性开启了HTTP架构的“双工”机制。
HEAD: 允许客户端以HEAD方法,只获取服务器的资源概览信息,而不真正获取具体的数据,如客户端查询Request-URI指定的资源是否过期,该方法在某些基于SOAP框架的业务中被采用,获取资源索引文件XML结构的文档,另通过抓包分析发现该方法也有用于获取服务器节点信息的,这取决于业务需求和应用开发设计理念了。 - Cache功能
HTTP1.0支持缓存特性,HTTP头部引入Cache-Control由服务器端决定是否客户端缓存行为、通过If-Modified-Since,Expires字段来判断缓存是否过期。
- MIME(多用途互联网邮件扩展类型):RFC 2045-2049*
-
http/1.1 1997年1月发布
RFC参考文献:https://www.ietf.org/rfc/rfc2616.txt
新功能特性: 支持持久连接、加强缓存功能、正式引入新的HTTP方法:PUT、PATCH、OPTIONS、DELETE- 持久连接
http/1.1协议最重要的一个特性就是引入持久连接,即HTTP keepalive机制,将TCP连接视为管理,在同一个TCP会话中传送多条HTTP事务。少了建立和关闭连接的消耗和延迟,弥补了HTTP1.0每次请求都要创建连接的缺点。大多数浏览器允许同时建立6个持久连接,每个连接可以传送多条HTTP请求。
HTTP请求头部引入Connection: keep-alive字段是HTTP1.1中持久连接的一个体现。
新的问题: 所有的数据通信是按次序进行的。服务器只能顺序处理回应,前面的回应慢,会有许多请求排队,造成"队头堵塞"(Head-of-line blocking)
解决方案: 一是减少请求数,二是同时多开持久连接,Apache HTTPD中通过KeepAliveTimeout限制持久连接超时长,MaxKeepAliveRequests限制每个TCP会话的处理最大HTTP事务数量。
抓包分析:
如下图所示: TCP一条TCP会话完成了9个HTTP事务,并且服务器开启了HTTP持久连接,超时时间为130秒,客户端在完成9条请求后就没有再发起其实请求,但是TCP会话并没有拆除,而会等在130秒后由服务器发出TCP Reset报文重置TCP会话,此种情况在高并发业务场景下或受到DDOS攻击,则有TCP连接资源被耗尽的风险。因此在生产环境,应该结合自己WEB页面首屏加载资源的数量来平衡KeepAliveTimeout和MaxKeepAliveRequests两个参数的值。
- 加强缓存功能
HTTP1.1引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。 - 新的HTTP方法
HTTP1.1正式支持:PUT、PATCH、OPTIONS、DELETE方法,这些方法在1.0中只是作为额外方法作以介绍,但并未正式推广。
- 持久连接
-
HTTP1.0和HTTP1.1的区别
- 缓存处理: 在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
- 带宽优化及网络连接的使用: HTTP1.0中,存在一些浪费带宽的现象,例如:客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),方便了开发者自由的选择以便于充分利用带宽和连接错误通知的管理,在HTTP1.1中新增24个状态响应码,如409(Conflict)表示请求的资源与资源当前状态冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- Host头处理: 在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)
- 持久连接: HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,弥补了HTTP1.0每次请求都要创建连接的缺点。
-
HTTP1.0和1.1的问题
- HTTP1.x在传输数据时,每次都需要重新建立连接,无疑增加了大量的延迟时间,特别是在移动端更为突出。
- HTTP1.x在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,无法保证数据的安全性。
- HTTP1.x在使用时,header里携带的内容过大,增加了传输的成本,并且每次请求header基本不怎么变化,尤其在移动端增加用户流量,虽然HTTP1.x支持了keep-alive,来弥补多次创建连接产生的延迟,但是keep-alive使用多了同样会给服务端带来大量的性能压力,并且对于单个文件被不断请求的服务(例如图片存放网站),keep-alive可能会极大的影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间。
-
SPDY协议
SPDY:2009年,谷歌研发,综合HTTPS和HTTP两者有点于一体的传输协议。- 降低延迟,针对HTTP高延迟的问题,SPDY优雅的采取了多路复用(multiplexing)。多路复用通过多个请求stream共享一个tcp连接的方式,解决了HOL blocking的问题,降低了延迟同时提高了带宽的利用率。
- 请求优先级(request prioritization)。多路复用带来一个新的问题是,在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY允许给每个request设置优先级,重要的请求就会优先得到响应。比如浏览器加载首页,首页的html内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,可以保证用户能第一时间看到网页内容
- header压缩。HTTP1.x的header很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。
- 基于HTTPS的加密协议传输,大大提高了传输数据的可靠性。
- 服务端推送消息推送(server push),采用了SPDY的网页,例如网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了。
-
HTTP2协议
http/2.0:2015年,HTTP2.0是SPDY的升级版
RFC参考文献:https://www.rfc-editor.org/rfc/rfc7540.txt- 头信息和数据体都是二进制,称为头信息帧和数据帧
- 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,且不用按顺序一一对应,避免了“队头堵塞“,此双向的实时通信称为多工(Multiplexing)。
- 引入头信息压缩机制(header compression),头信息使用gzip或compress压缩后再发送;客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,不发送同样字段,只发送索引号,提高速度。
- HTTP/2 允许服务器未经请求,主动向客户端发送资源,即服务器推送(server push)。
-
HTTP2.0和SPDY区别:
- HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
- HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE
二、HTTP工作原理
1.HTTP通信模型
核心思想:HTTP由TCP承载,HTTP作为TCP的净载被封装在TCP报文内
2. 服务器端
- 服务器应用程序向内核发起socket系统调用创建套接字(文件)
- 应用程序申请Socket成功后,会使用bind()系统调用户绑定创建的套接字
- 套接字绑定成功后会将应用进程将Socket置为listen()状态
Accept()负责接收客户端的请求,如果没有客户端请求则该进程一直处理阻塞状态。
3. 客户端
- 客户端应用程序同样向内核发起Soket系统调用创建临时套接字(文件)
- 套接字创建成功后会使用Connect()系统调用向服务器IP发送TCP会话建立连接请求(所以才有客户端发SYN,服务器端也发送SYN+ACK,客户端ACK后一个TCP的双工会话建立成功)
- TCP会话建立成功后客户端使用Write()系统调用向套接字文件中写入数据(发送数据请求),可以将套接字理解成为一个逻辑管道,客户端用Write()向管道一端输入数据,服务器端用Read()从另一端读取客户端发送的数据,并向服务器端应用程序提交数据。同时服务器也用Write()向该套接字文件中写入处理的请求结果,将发送给客户端,客户端也会Read()读取服务器的处理结果,并向上层应用程序提交,如此反复读写完成本次会话所有的交互数据所以才有了网络I/O的概念。
- 读写完成本次会话所有的交互数据后,双方都需要使用Close()系统调用来拆除TCP会话,也就是发送FIN完成TCP四大次挥手操作。一般是谁发送的请求谁先发FIN负责拆除会话。
4.HTTP 抓包分析
以下是HTTP1.1协议事务的完整交互过程,展现了HTTP1.1的重点特性,其交互流程如下:
- TCP流的前3号包:客户端发起TCP三次握手。
- TCP流的第4号名:客户端HTTP请求。
- TCP流的第5号包:服务器ACK客户端的HTTP请求,但并不是真正的响应报文。
- TCP流的第6号包:服务器响应体报文的第一个包。
- TCP流的第24-35号包:KeepAlived会话保持
- TCP流的第36-39号包:TCP会话四次挥手过程。
5.浏览器都做了哪些工作
- 浏览器初始化HTTP请求任务
- 浏览器调用域名解析函数,提取地址栏URL中FQDN解析域名
- 先查本地DNS缓存
- 发起域名解析请求
- 获取域名IP地址后,向操作系统内核发起Soket系统调用创建临时套接字,与服务器建立TCP连接
- 浏览器构造并发送HTTP请求。
- 服务器收到HTTP请求,构造响应报文,响应给客户端。
- 客户端首次访问,则直接构造响应报文,响应给客户端
- 客户端非首次访问,并且请求报文头部没有携带缓存查询字段,则直接构造响应报文,响应给客户端。
- 客户端非首次访问,根据请求报文头部携带缓存查询字段,来判断客户端缓存是否过期,没过期则返回HTTP 304,通知客户端缓存的内容没有发生变化。
- 客户端收到服务器的响应内容后,进行内容解析及网页页面渲染,生成网页。
- 生成DOM树:根据HTML Document(每个页面加载的第一个元素)基于W3C文档对象规范,生成DOM树。
- 根据DOM树加载各叶子节点的资源,如CSS、JS、图片等。
- 解析JS并作用于DOM树,使用DOM树具体灵魂。
- 解析CSS并作用于经过JS改造过的DOM树,做排版操作生成渲染树
- 基于渲染树呈现页面内容。
- HTTP事务完成,服务器记录访问日志,拆除TCP连接
- TCP会话拆除过程不一定就是服务器主动拆除,正常情况收客户端主动发起会话拆除,对于开启HTTP keepalive的服务器,如果客户端不主动拆除,则在达到KeepAliveTimeout时间后,服务器会采用TCP Reset强制拆除。
网页加载过程如下图所示:
- TCP会话拆除过程不一定就是服务器主动拆除,正常情况收客户端主动发起会话拆除,对于开启HTTP keepalive的服务器,如果客户端不主动拆除,则在达到KeepAliveTimeout时间后,服务器会采用TCP Reset强制拆除。
三、HTTP报文结构
1.请求报文
- HTTP请求行:<HTTP方法> <请法的URI> <HTTP版本号>
- HTTP头部信息
- HTTP消处实体
- 例:HTTP报文解析
- GET /wp-content/themes/js/share.js? HTTP/1.1 //HTTP 方法、URI、协议版本三部分构成了请求行
- Host: www.aaaa.com //请求资源隶属于绑定在哪个域名下的主机
- Connection: keep-alive //要求开启HTTP持久连接
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) //声明客户端程序类型,这个很有用,可以根据手机系统类型来调度业务。
- Accept: / //声明客户端本次请求信息的mime类型
- Referer: http://www.magedu.com/ //Referer:指定是从哪个页面发次本次请求的
- Accept-Encoding: gzip, deflate //Accept-Encoding:声明客户端支持哪些编码
- Accept-Language: zh-CN,zh;q=0.9 //声明客户端支持哪种语言
- Cookie: //服务器分配给客户端的唯一标识,类似访问令牌有时效性
抓包实例:
2.响应报文
- HTTP响应行:
- HTTP头部信息
- HTTP响应实体
- 例:
- HTTP/1.1 200 OK //HTTP协议版本、响应状态码、状态描述三部分构成HTTP响应行
- Server: Tengine //服务器端WEB平台类型
- Date: Mon, 09 Dec 2019 05:18:38 GMT //HTTP消息发送时间,北京时间=GMT+8小时
- Content-Type: application/javascript //声明响应体的MIME类型
- Last-Modified: Sun, 23 Dec 2018 12:17:44 GMT //请求资源文件上次修改时间
- Transfer-Encoding: chunked //传输编码方式:chunked分块传输,服务器不需要知道整个文件大小,只管封装就可以了,数据重组反正是对端的事情。
- Connection: keep-alive //声明本次连接为持久链接
- Vary: Accept-Encoding //Vary是HTTP头部自定义字段,其值可以是其他遵循HTTP约定的值。
- Expires: Mon, 16 Dec 2019 05:18:38 GMT //本次响应内容的过期时间,在字段date到Expries字段时间内,客户端再需要该资源时将直接调用本地缓存,而不需要再到服务器获取
- Cache-Control: max-age=604800 //声明缓存的最大有效期,单位为秒,604800为1天,供其它缓存服务器衡量资源是否过期。
- Content-Encoding: gzip //声明响应内容编码方式。
- 例:抓包解析
四、HTTP状态码
待续……
五、HTTP方法
待续……