首先我们知道TCP的连接,它包含了三个过程,建立连接、传输数据、断开连接。
HTTP协议,它正是建立在TCP连接基础上的。HTTP是一种允许浏览器向服务器获取资源的协议,是Web的基础。
了解一下之后,我们来带着下面的这些疑问,一步一步的走进HTTP吧:
- 为什么有些网站, 第一次打开慢, 第二次快一些???
- 当登录过一个网站之后, 下次再访问, 自动就是登录状态了???
浏览器发起HTTP请求流程
当我们在网站输入一个网址的时候, 比如http://www.baidu.com/index.html(只是打个比方), 浏览器会完成哪些动作?
1. 构建请求
首先,浏览器构建请求行信息(如下所示), 构建好后,浏览器准备发起网络请求。
GET /index.html HTTP1.1
2. 查找缓存
在发送请求之前, 浏览器会现在它缓存中查询是否有要请求的文件。当浏览器发现缓存中有存在的副本, 他就会拦截请求, 返回该资源的副本, 并直接结束请求, 而不会再去源服务器重新下载。
这样做的好处很明显吧:
- 缓解服务器端压力, 提升性能(获取资源的耗时更短了);
- 对于网站来说, 缓存是实现快速资源加载的重要组成部分。
3. 准备IP地址和端口
让我们先来看看HTTP和TCP的关系。HTTP协议是作为应用层协议, 用来封装请求的文本信息; 并使用TCP/IP作为传输层协议将它发送到网络上, 所以在HTTP开始工作之前,浏览器需要先通过TCP与服务器建立连接。这样就能理解, HTTP的内琼是通过TCP的传输数据阶段来实现的。
我们来看下面这张图, 加深一下理解:
我们知道访问一个网站需要的是IP,当然还有端口, 但是当我们输入百度的网址时, 会发现URL上并没有IP, 咋回事呢??
这里来介绍一套能将输入的域名(www.baidu.com)映射为IP的系统, 这套系统叫做"域名系统", 简称DNS。
当我们输入网址的时候, 其实他会先在本地查找是否有缓存这个域名的IP, 如果没有他就会去DNS服务器上查找对应的IP地址, 如果找到DNS服务器会返回你得IP地址并且缓存到浏览器中(DNS缓存), 当然缓存服务是浏览器提供的。那这样我们下次在输入相同域名的时候, 直接就可以从缓存中取出IP, 拼上端口进行请求了。
通常情况下, 如果URL没有特别知名端口号, 那么HTTP协议默认是80端口。
然后就会进行下一步
4. 等待TCP队列
不应该是三次握手么?不不不,还没到,Chrome有一个机制, 同一个域名同时最多只能建立6哥TCP连接, 如果在同一个域名下同时有10哥请求发生, 那么其中4个请求会进入排队等待状态, 直到进行中的请求完成。
如果,当前的请求数量少于6, 会直接进行下一步, 建立TCP连接。
5. 建立TCP连接
三次握手开始,如果不明白请看我上一篇文章
6. 发送HTTP请求
建立了TCP连接之后, 浏览器如何发送请求给服务器的???
我们看图来理解:
首先浏览器向服务器发送请求行, 它包括了请求方法、请求url和HTTP版本协议。
请求行会告诉服务器,浏览器需要什么资源, 最常用的是GET请求。
但是我们有时候还需要用POST请求向服务器传递我们准备的数据, 这些数据就会在请求体中进行携带。
请求头会携带一些基础信息, 发送给服务器。比如Cookie、浏览器的操作系统、当前请求的域名信息等。
走过千山与万水, 我们就需要等待服务器处理HTTP请求, 然后返回给我们数据了。
服务器端处理HTTP请求流程
1. 返回请求
服务器处理结束之后, 就会返回数据给浏览器了。我来看下面这个图,理解他们之间的关系:
首先服务器会返回响应行,包括协议版本和状态码。
好像看到了熟悉的东西....状态码。没错,就是他,代表着返回的状态,例如200表示成功,404找不到页面...
随后, 服务器会向浏览器发送响应头。响应头包含了服务器的一些信息,比如:服务器生成返回时间、返回的数据类型(JSON、HTML、流媒体等类型), 以及客户端保存的Cookie信息等。
发送完响应头后, 服务器就可以继续发送响应体的数据,通常,响应体就包含了HTML的实际内容。
发送完了这些就可断开连接了。
2. 断开连接
正常情况下要进行TCP的四次挥手了,如果浏览器或者服务器想要在请求结束之后继续保持连接, 那就在信息头中加入:
Connection:Keep-Alive
这样会让TCP始终保持开启状态。保持开启状态可以省去下次需要建立连接的时间,提升资源加载速度。
3. 重定向
我们在浏览器中输入baidu.com, 你会发现最终打开的地址是https://www.baidu.com/, 这就是将你输入的网址重新定向到一个新的网址, 从而打开了一个正确的网站。
回到我们开始的问题:
1. 为什么很多网站第二次打开的时候会很快?
除了DNS缓存, 还有浏览器资源缓存, 大大提升了第二次打开页面的速度。
我们来看一下浏览器资源缓存的过程:
通过第一次请求, 我们可以看出当服务器返回HTTP响应头给浏览器的时候, 浏览器是通过响应头中的Cache-Control字段来设置是否缓存该资源。
我们需要为缓存设置一个过期时长, 而这个时长是通过Cache-Control中的Max-age参数来设置的。
Cache-Control:Max-age:2000
其中的流程是这样的:
- 浏览器发送请求给服务器之前, 会查看是否有缓存,是否过期, 有缓存没过期直接返回缓存中的资源, 给浏览器。
- 如果过期, 准备IP端口, 建立TCP连接, 发送HTTP请求, 并且会在请求头中带上
If-None-Match:"4f80f-13c-3a1xb12a"
- 而服务器收到请求头之后,会根据If-None-Match的值来判断请求的资源是否更新过。如果没有返回304状态码, 告诉浏览器请继续使用缓存。如果更新了, 返回更新数据。
2. 登录状态是怎么保持的?
在用户登陆, 输入了用户名密码, 点击确认之后。发生了什么呢?我们来看一下下面这个图:
- 首先, 浏览器会提交信息给服务器, 查询后台, 验证用户信息是否正确, 如果正确就会生成一个表名用户身份字符串, 并把该字符串写到响应头的Set-Cookie字段里
Set-Cookie:UID=3431uad
。 - 浏览器收到服务器的响应头之后, 开始解析, 如果遇到响应头中含有Set-Cookie字段,保存到浏览器本地。
- 当用户再次访问的时候, 浏览器读取之前保存的Cookie数据, 并放在请求头里面
Cookie: UID=3431uad
, 然后发起HTTP请求。 - 服务器接收到请求头数据之后, 查找携带的Cookie字段信息, 查询到之后判断用户已是登陆状态, 然后生成含有该用户信的的页面数据, 再返回给浏览器。
- 浏览器在接受到含有用户的页面数据之后, 正确的展示用户登录状态的信息。
这就是登录时候, HTTP请求的过程。
总结:
本章节结合之前, 比较杂乱, 我们来用图总结一下包含之前的知识:
- 浏览器构建请求
- 浏览器查找有关本次请求的缓存
- 存在就用,不存在请求DNS,查找IP,准备端口
- TCP等待队列
- TCP三次握手建立连接
- 发起HTTP请求,发送请求报文。请求行、请求头、请求体。
- 服务器处理请求,解析请求报文。
- 服务器响应请求,发送响应报文。响应行、响应头、响应体。
- 断开TCP连接。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。