浏览器下的一次网络请求流程

浏览器下的一次网络请求流程

以输入 http://github.com/appleguardu... web 请求本质上就是一台主机去另外一台主机获取对应的资源.css

1.进程切换

当导航栏输入 http://github.com/appleguardu... 浏览器进程把这个url交给网络进程处理, 给我去这台主机下取资源;html

2.解析请求的URL,DNS查询IP,准备端口

  • URL: 统一资源定位符
protocol: 协议头, 譬若有http,ftp等
host: 主机域名或IP地址
port: 端口号
path: 目录路径
query: 即查询参数
fragment: 即#后的hash值,通常用来定位到某个位置
  • DNS(域名与IP的映射系统)
因为不一样主机之间都是经过IP地址来肯定的,因此首先会进行域名解析,查询; 
浏览器会向域名服务器去查询http://github.com对应的Ip.

//  Ip查询也有一套优化机制: 缓存机制(能够减小网络请求)
浏览器缓存:   浏览器会按照必定的频率缓存 DNS 记录;
操做系统缓存: 若是浏览器缓存中找不到须要的 DNS 记录,那就去操做系统中找;
路由缓存:     路由器也有 DNS 缓存;
ISP(互联网服务提供商)的DNS服务器: ISP 有专门的 DNS 服务器应对 DNS 查询请求;
根服务器: ISP 的 DNS 服务器还找不到的话,它就会向根服务器发出请求,进行递归查询;
(DNS 服务器先问根域名服务器.com 域名服务器的 IP 地址,而后再问.github 域名服务器,依次类推)
  • 端口port
若是不是特别指定,http协议默认的80端口, https: 443

3.等待 TCP 队列(浏览器对tcp的限制)

chorome浏览器有个机制, 统一域名下同时最多只能创建 6 个 TCP链接(浏览器的限制可能不同), 若是超过 6 个请求, 那么剩下的会进入排队等待的状态, 等待前面的完过后本身再去创建链接node

4.创建 TCP 链接

TCP 协议git

TCP运行: 链接建立、数据传送和链接终止
  • 链接建立: 三次握手(保证可靠传输)
1.客户端经过向服务器端发送一个SYN来建立一个主动打开,做为三次握手的一部分;
客户端把这段链接的序号设定为随机数A。

2.服务器端应当为一个合法的SYN回送一个SYN/ACK。
ACK的确认码应为A+1,SYN/ACK包自己又有一个随机产生的序号B。

3.最后,客户端再发送一个ACK。此时包的序号被设定为A+1,而ACK的确认码则为B+1。
当服务端收到这个ACK的时候,就完成了三次握手,并进入了链接建立状态。

client侧: SYN         ACK
server侧:     SYN+ACK
  • 数据传输(一些机制)
使用序号,对收到的TCP报文段进行排序以及检测重复的数据;
使用校验和检测报文段的错误,即无错传输;
使用确认和计时器来检测和纠正丢包或延时;
流量控制(Flow control);拥塞控制(Congestion control);丢失包的重传。
  • 链接终止(四次挥手)
链接终止使用了四路握手过程(或称四次握手,four-way handshake),在这个过程当中链接的每一侧都独立地被终止。
当一个端点要中止它这一侧的链接,就向对侧发送FIN,对侧回复ACK表示确认。
所以,拆掉一侧的链接过程须要一对FIN和ACK,分别由两侧端点发出。

client侧: FIN          ACK
server侧:     ACK  FIN

5.发送 HTTP 请求

当 TCP 链接创建以后, 浏览器与服务器之间开始通讯,传输数据github

构建请求报文

  • 请求行
GET /appleguardu HTTP/1.1
// 请求方式:(Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE
// 资源路径URI: /appleguardu
// 协议版本: HTTP 1.1
  • 请求头(经常使用的)
Accept: 接收类型,表示浏览器支持的MIME类型(对标服务端返回的Content-Type)
Accept-Encoding: 浏览器支持的压缩类型,如gzip等,超出类型不能接收
Content-Type: 客户端发送出去实体内容的类型
Cache-Control: 指定请求和响应遵循的缓存机制,如no-cache
If-Modified-Since: 对应服务端的Last-Modified,用来匹配看文件是否变更,只能精确到1s以内,http1.0中
Expires: 缓存控制,在这个时间内不会请求,直接使用缓存,http1.0,并且是服务端时间
Max-age: 表明资源在本地缓存多少秒,有效时间内不会请求,而是使用缓存,http1.1中
If-None-Match: 对应服务端的ETag,用来匹配文件内容是否改变(很是精确),http1.1中
Cookie: 有cookie而且同域访问时会自动带上
Connection: 当浏览器与服务器通讯时对于长链接如何进行处理,如keep-alive
Host: 请求的服务器URL
Origin: 最初的请求是从哪里发起的(只会精确到端口),Origin比Referer更尊重隐私
Referer: 该页面的来源URL(适用于全部类型的请求,会精确到详细页面地址,csrf拦截经常使用到这个字段)
User-Agent: 用户客户端的一些必要信息,如UA头部等
  • 请求体
post 请求中参数常放在请求体中
如参数的序列化形式(a=1&b=2这种;
或者直接放表单对象(Form Data对象,上传时能够夹杂参数以及文件的等

注意: 若是请求的是缓存资源,则会终止请求

浏览器会对请求的文件资源进行检查, 若是这个请求的资源存在于浏览器缓存当中, 请求就会被拦截, 浏览器直接从本地缓存中获取后发给网络进程, 并结束此处请求过程
关于http缓存介绍web

缓存分类

缓存能够简单的划分红两种类型: 强缓存(200 from cache)与协商缓存(服务端返回304);
强缓存: 浏览器若是判断本地缓存未过时,就直接使用,无需发起http请求;
协商缓存304: 当浏览器再次向服务端发起http请求,而后服务端(304)告诉浏览器文件未改变,让浏览器使用本地缓存apache

  • 如何区分两类缓存? 经过设置 http 头部信息
# 几种头部缓存属性
强缓存(http1.1): Cache-Control/Max-Age 
强缓存(http1.0): Pragma/Expires 

协商缓存(http1.1): If-None-Match/E-tag
协商缓存(http1.0): If-Modified-Since/Last-Modified

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
HTML页面中也有一个meta标签能够控制缓存方案-Pragma,不过通常都是服务端设置
  • http1.0下的缓存控制
Pragma: 严格来讲,它不属于专门的缓存控制头部,可是它设置no-cache时可让本地强缓存失效(属于编译控制,来实现特定的指令,主要是由于兼容http1.0,因此之前又被大量应用)

Expires: 服务端配置的,属于强缓存,用来控制在规定的时间以前,浏览器不会发出请求,而是直接使用本地缓存,
注意: Expires通常对应服务器端时间,如Expires: Fri, 30 Oct 1998 14:19:41
若是客户端时间和服务端不一样步,可能形成浏览器本地的缓存无用或者一直没法过时

If-Modified-Since/Last-Modified: 这两个是成对出现的,属于协商缓存的内容;
其中浏览器的头部是If-Modified-Since,而服务端的是Last-Modified;
它的做用是,在发起请求时,若是If-Modified-Since和Last-Modified匹配,
那么表明服务器资源并未改变,所以服务端不会返回资源实体,而是只返回头部,通知浏览器可使用本地缓存...
Last-Modified,顾名思义,指的是文件最后的修改时间,并且只能精确到1s之内
注意: 若是服务端的文件会周期性的改变, 致使缓存失效
  • http1.1下的缓存控制
Cache-Control: 缓存控制头部,有no-cache、max-age等多种取值

Max-Age: 服务端配置的,用来控制强缓存,在规定的时间以内,浏览器无需发出请求,直接使用本地缓存,
注意,Max-Age是Cache-Control头部的值,不是独立的头部,
譬如Cache-Control: max-age=3600,并且它值得是绝对时间,由浏览器本身计算

If-None-Match/E-tag: 这两个是成对出现的,属于协商缓存的内容;
其中浏览器的头部是If-None-Match,而服务端的是E-tag,
一样,发出请求后,若是If-None-Match和E-tag匹配,则表明内容未变,通知浏览器使用本地缓存;
和Last-Modified不一样,E-tag更精确,它是相似于指纹同样的东西,因此会优先级也更高...
基于FileEtag INode Mtime Size生成,也就是说,只要文件变,指纹就会变,并且没有1s精确度的限制。

6.服务器处理 http 请求

当服务器接收到浏览器的请求报文后, 会交给对应的处理程序进行处理(此处省略...),而后想服务器返回响应报文json

响应报文

  • 响应行
HTTP/1.1 200 OK
// 协议版本 状态码 状态码信息
// 200——代表该请求被成功地完成,所请求的资源发送回客户端
// 304——自从上次请求后,请求的网页未修改过,请客户端使用本地缓存
// 400——客户端请求有错(譬如能够是安全模块拦截)
// 401——请求未经受权
// 403——禁止访问(譬如能够是未登陆时禁止)
// 404——资源未找到
// 500——服务器内部错误
// 503——服务不可用
  • 响应头(经常使用的)
Access-Control-Allow-Headers: 服务器端容许的请求Headers
Access-Control-Allow-Methods: 服务器端容许的请求方法
Access-Control-Allow-Origin: 服务器端容许的请求Origin头部(譬如为*)
Content-Type: 服务端返回的实体内容的类型
Date: 数据从服务器发送的时间
Cache-Control: 告诉浏览器或其余客户,什么环境能够安全的缓存文档
Last-Modified: 请求资源的最后修改时间
Expires: 应该在何时认为文档已通过期,从而再也不缓存它
Max-age: 客户端的本地资源应该缓存多少秒,开启了Cache-Control后有效
ETag: 请求变量的实体标签的当前值
Set-Cookie: 设置和页面关联的cookie,服务器经过这个头部把cookie传给客户端
Keep-Alive: 若是客户端有keep-alive,服务端也会有响应(如timeout=38)
Server: 服务器的一些相关信息
  • 响应体
响应体通常是服务端须要传给客户端的内容;
如接口请求时: 实体中就是对应的信息的 json格式对象
如页面请求时: 实体中就是对应的 html 字符串

注意

通常来讲, 请求头部和响应头部是互相匹配的
如请求头部的Accept要和响应头部的Content-Type匹配,不然会报错;
跨域请求时,请求头部的Origin要匹配响应头部的Access-Control-Allow-Origin,不然会报跨域错误
还有在使用缓存时,
请求头部的If-Modified-Since、If-None-Match分别和
响应头部的Last-Modified、ETag相对应跨域

以上基本都是经过服务端程序来控制的浏览器

重定向

当响应状态码是 301 时,会发生重定向, 浏览器进程从新让导航进行工做, 修改 location 字段中的地址,继续上述的请求流程

8.浏览器解析并渲染页面

浏览器进程开始调度, 渲染进程经过管道接受网络进程的html数据,开始解析html工做

渲染进程工做流

  • 1.DOM Tree 构建
当渲染进程接收到导航的确认信息,开始接受HTML数据时,主线程会解析文本字符串为 DOM;
这里依靠 HTMl 解析器: 
接受字节流 -> 维护 token 栈 -> 生成节点node -> 组成 DOM;

遇到内嵌 script 时, DOM解析工做中止; js引擎介入执行(可能会修改dom结构);
执行完 js 后恢复解析工做, 因此 js 会阻塞 dom 解析.

遇到其余内联资源时(css,img)会通知网络进程去下载, 特别是 css;
js 在操做dom 样式时会依赖cssom,生成 layoutTree也须要 cssom; 
因此 css 又会阻塞 js 的执行
  • 2.样式计算, 构建cssom(css规则树)
这里会基于 CSS 选择器解析 CSS 获取每个节点的最终的计算样式值;
对应的就是styleSheets
  • 3.计算布局, 生成layout tree
想要渲染一个完整的页面,除了获知每一个节点的具体样式,还须要获知每个节点在页面上的位置,
布局实际上是找到全部元素的几何关系的过程。

这里经过遍历 DOM 及相关元素的计算样式,主线程会构建出包含每一个元素的坐标信息及盒子大小的布局树。
布局树和 DOM 树相似,可是其中只包含页面可见的元素,若是一个元素设置了 `display:none` ,
这个元素不会出如今布局树上,伪元素虽然在 DOM 树上不可见,可是在布局树上是可见的。
  • 4.分层,绘制(layer -> paint)
为特定的节点生成专用图层(will-change属性), 生成 图层树;
为图层生成绘制表(记录了绘制指令和顺序), 提交到合成线程
  • 5.分块,光栅化
合成线程将图层分为图块, 经过光栅化生成位图(GPU 进程)
  • 6.合成,显示
图块被光栅化后会生成一个绘制命令, 经过 IPC 提交给浏览器进程去执行,
绘制到内存中而后展现在显示器上

9.断开TCP链接

当数据传送完毕,须要断开 tcp 链接,此时发起 tcp 四次挥手;
一般状况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 链接。
不过若是浏览器或者服务器在其头信息中加入了

Connection: Keep-Alive (http/1.1下默认启用, http/1.0默认close)
// keep-alive不会永远保持,它有一个持续时间,通常在服务器中配置(如apache,
另外长链接须要客户端和服务器都支持时才有效

TCP 链接在发送后将仍然保持打开状态,这样浏览器就能够继续经过同一个 TCP 链接 发送请求。
保持 TCP 链接能够省去下次请求时须要创建链接的时间,提高资源加载速度。 好比,一个 Web 页面中内嵌的图片就都来自同一个 Web 站点,若是初始化了一个持久连 接,你就能够复用该链接,以请求其余资源,而不须要从新再创建新的 TCP 链接。

参考

TCP 协议百科
HTTP headers

  • http2.0 了解
- 多路复用(即一个tcp/ip链接能够请求多个资源)
- 首部压缩(http头部压缩,减小体积)
- 二进制分帧(在应用层跟传送层之间增长了一个二进制分帧层,改进传输性能,实现低延迟和高吞吐量)
- 服务器端推送(服务端能够对客户端的一个请求发出多个响应,能够主动通知客户端)
- 请求优先级(若是流被赋予了优先级,它就会基于这个优先级来处理,由服务器决定须要多少资源来处理该请求。)
相关文章
相关标签/搜索