HTTP 请求的完整过程
一次 HTTP 请求的整个过程包括:DNS 解析、建立 TCP 连接、客户端请求、服务端响应、断开 TCP 连接。 本文主要从以上几个方面来讲解一次完整的 HTTP 请求。
HTTP 起源
今天我们能够在网络中畅游,都得益于一位计算机科学家蒂姆·伯纳斯·李的构想。1991 年 8 月 6 日,蒂姆·伯纳斯·李在位于欧洲粒子物理研究所(CERN)的 NeXT 计算机上,正式公开运行世界上第一个Web网站,建立起基本的互联网基础概念和技术体系,由此开启了网络信息时代的序幕。
伯纳斯·李的提案包含了网络的基本概念并逐步建立了所有必要的工具:
提出 HTTP (Hypertext Transfer Protocol) 超文本传输协议,允许用户通过单击超链接访问资源。
提出使用HTML超文本标记语言(Hypertext Markup Language)作为创建网页的标准。
创建了统一资源定位器 URL (Uniform Resource Locator)作为网站地址系统,就是沿用至今的 http://www URL 格式。
创建第一个 Web 浏览器,称为万维网浏览器,这也是一个 Web 编辑器。
创建第一个 Web 服务器以及描述项目本身的第一个Web页面。
HTTP 协议一共有五大特点:
支持客户/服务器模式。
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由 Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态:无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息(Cookie 和 Session 孕育而生,后期再讲)。
DNS 解析
DNS( Domain Name System) 是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于 TCP/IP 网络,它所提供的服务是用来将主机名和域名转换为 IP 地址的工作。
关于 DNS 的获取流程:
DNS 是应用层协议,事实上他是为其他应用层协议工作的,包括不限于 HTTP 和 SMTP 以及 FTP,用于将用户提供的主机名解析为 ip 地址。具体过程如下:
用户主机上运行着 DNS 的客户端,就是我们的 PC 机或者手机客户端运行着 DNS 客户端。
浏览器将接收到的 url 中抽取出域名字段,就是访问的主机名,比如
http://www.baidu.com/
,并将这个主机名传送给 DNS 应用的客户端。DNS 客户机端向 DNS 服务器端发送一份查询报文,报文中包含着要访问的主机名字段(中间包括一些列缓存查询以及分布式 DNS 集群的工作)。
该 DNS 客户机最终会收到一份回答报文,其中包含有该主机名对应的 IP 地址。
一旦该浏览器收到来自 DNS 的 IP 地址,就可以向该IP地址定位的 HTTP 服务器发起 TCP 连接。
建立 TCP 连接
相信大家都知道 HTTP 是一个基于 TCP/IP 协议簇来传递数据。TCP/IP 协议在进行连接的时候都需要进行三次握手,所以 HTTP 在连接服务器的时候也需要进行三次握手。
TCP/IP 是互联网相关的各类协议簇的总称。也有另一种说法 TCP/IP 是 TCP 和 IP 两种协议。 TCP/IP 四层模型如下:
TCP 报文包 = TCP 头信息 + TCP 数据体,而在 TCP 头信息中包含了 6 种控制位(上图红色框中),这六种标志位就代表着 TCP 连接的状态:
SYN:表示请求建立一个连接(同步序号)
URG:紧急数据(urgent data)—这是一条紧急信息
ACK:确认已收到(确认序号)
PSH:尽可能快地将数据送往接收进程
RST:表示要求对方重新建立连接
FIN:表示通知对方本端已经完成数据发送,要关闭连接了
TCP 建立连接过程 --- 三次握手
过程说明:
客户端发送位码为 syn=1,随机产生 seq number=1234567 的数据包到服务器,服务器由SYN=1知道客户端要求建立联机(客户端:我要连接你)
服务器收到请求后要确认联机信息,向 A 发送ack number=(客户端的seq+1),syn=1,ack=1,随机产生seq=7654321的包(服务器:好的,你来连吧)
客户端收到后检查 ack number 是否正确,即第一次发送的 seq number+1 ,以及位码 ack 是否为1,若正确,客户端会再发送 ack number=(服务器的seq+1),ack=1,服务器收到后确认seq值与ack=1则连接建立成功。(客户端:好的,我来了)
注意注意注意,重要的问题说三次:为什么 http 建立连接需要三次握手,不是两次或四次?
个人理解:确认双方信道可以实现最低限度的全双工(可以合并第 2,3 步),三次是最少的安全次数,两次不安全,四次浪费资源。
如果觉得理解不对的,可以下方留言或者在 issue 里面去讨论。
客户端请求
三次握手之后,客户端和服务端的连接就已经建立好了,客户端就可以向服务器端发送 HTTP 请求。
HTTP 请求报文结构
TCP 报文包 = TCP 头信息 + TCP 数据体,TCP 头信息的结构如下:
TCP 数据体,也就是 HTTP 请求报文。结构如下:
HTTP 请求实例
①是请求方法,HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的两种 GET 和 POST,如果是 RESTFUL 接口的话一般会用到 GET、POST、DELETE、PUT。
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL
③是协议名称及版本号
④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息
⑤是报文体,GET 方法 username=tommyyang&userid=168168 通过请求 URL 传递参数,如“/settings/user_has_gravatar?username=tommyyang&userid=168168”的方式传递请求参数。
参数说明如下
: Host: 域名。 Connection: 连接状态。 User-Agent:客户端使用的操作系统和浏览器的名称和版本,有些网站会限制请求浏览器。 Referer:跳转到该网页的地址,表示此请求来自哪里,有些网站会限制请求来源。
服务端响应
服务器在收到客户端请求,然后对请求处理完后需要响应并返回给客户端,而 HTTP 响应报文结构与请求结构体一致。
HTTP 响应报文结构
HTTP 响应报文结构与请求报文结构类似,包括:
报文首部。
空行(CR + LF),表示报文主体开始。
报文主体。
空行(CR + LF),表示报文主体结束。
结构如下:
响应状态码
HTTP 响应实例
① 报文协议及版本
② 状态码及状态描述
③ 响应头
④ 响应体
断开连接
在服务器响应完毕后,一次会话就结束了,这时候连接会断开么?
长短连接
是否断开,我们需要根据 HTTP 版本来确定:
HTTP/1.0 版本的时候,客户端与服务器完成一个请求/响应之后,会将之前建立的 TCP 连接断开,下次请求的时候又要重新建立 TCP 连接,
这也就是短连接。
在 HTTP1.0 发布仅半年后(1997年1月) ,HTTP/1.1 版本发布并带来一个新的功能:在客户端与服务器完成一次请求/响应之后,允许不断开 TCP 连接,
这意味着下次请求就直接使用这个 TCP 连接而不需要重新握手建立新连接,这也被称为长连接。
tips:长连接是指一次TCP连接允许多次HTTP会话,HTTP永远都是一次请求/响应,会话结束,HTTP本身不存在长连接之说。
早在 1999 年 HTTP1.1 就推广普及,现在浏览器在请求时请求头中都会携带一个参数:Connection:keep-alive,这表示浏览器要求与服务器建立长连接, 而服务器也可以设置是否愿意建立长连接。
长连接的优缺点
优点:当网站中有大量静态资源(图片、css、js等)被请求时就可以开启长连接,这些静态资源就可以通过一次 TCP 连接发送。
缺点:当客户端请求一次就不再请求时,服务器却一直开着长连接,资源被占用着,严重浪费资源。
断开连接过程
在建立 TCP 连接时是三次握手,而断开 TCP 连接是四次挥手。
TCP 断开连接过程 --- 四次挥手结构图如下:
在 TCP 连接建立的时候,讲到了标志位:FIN 表示通知对方自身要断开连接了。
注意注意注意,重要的问题说三次:为什么断开连接是四次挥手呢?
个人理解:由于 TCP 要支持半关闭连接。在建立连接的时候是全双工的,A <=> B 双方都可以读写。断开的时候需要支持半关闭,意味着 TCP 支持客户端和服务端双方独立关闭通道;因此会有两次独立的关闭写通道的请求。一次关闭请求(FIN),对应一个 ACK,也就有了四次挥手。
如果觉得理解不对的,可以下方留言或者在 issue 里面去讨论。
拓展
了解下 HTTP2.0。
HTTP & RPC,了解下 HTTP 与 RPC 的区别,为什么要使用 RPC?
HTTP & HTTPS,了解学习为什么现在应用更多的使用 HTTPS?
Last updated