当输入一个网址,例如www.baidu.com之后会发生以下事件:
域名解析 –> 发起TCP的3次握手 –> 建立TCP连接后发起http请求 –> 服务器响应http请求,浏览器得到html代码 –> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) –> 浏览器对页面进行渲染呈现给用户
以Chrome浏览器为例:
域名解析
首先浏览器会解析 url 所对应的 ip 地址。
- 浏览器会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有输入 url 对应的条目,而且没有过期。
注:可以使用 chrome://net-internals/#dns 来进行查看Chrome自身的缓存 - 如果浏览器自身的缓存里面没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存。
注:以Windows系统为例,可以在命令行下使用 ipconfig /displaydns 来进行查看操作系统自身的DNS缓存 - 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果有则解析成功。
- 浏览器发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求。运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先是会找根域的DNS的IP地址(这个DNS服务器都内置13台根域的DNS的IP地址),找打根域的DNS地址,就会向其发起请求(请问www.linux178.com这个域名的IP地址是多少啊?),根域发现这是一个顶级域com域的一个域名,于是就告诉运营商的DNS我不知道这个域名的IP地址,但是我知道com域的IP地址,你去找它去,于是运营商的DNS就得到了com域的IP地址,又向com域的IP地址发起了请求(请问www.linux178.com这个域名的IP地址是多少?),com域这台服务器告诉运营商的DNS我不知道www.linux178.com这个域名的IP地址,但是我知道linux178.com这个域的DNS地址,你去找它去,于是运营商的DNS又向linux178.com这个域名的DNS地址(这个一般就是由域名注册商提供的,像万网,新网等)发起请求(请问www.linux178.com这个域名的IP地址是多少?),这个时候linux178.com域的DNS服务器一查,诶,果真在我这里,于是就把找到的结果发送给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.linux178.com这个域名对应的IP地址,并返回给Windows系统内核,内核又把结果返回给浏览器,终于浏览器拿到了www.linux178.com对应的IP地址,该进行一步的动作了。
发起TCP的三次握手
TCP是一个端到端的可靠的面向连接的协议,所以HTTP基于传输层TCP协议不用担心数据的传输的各种问题。
建立TCP连接后发起HTTP请求
HTTP请求报文
请求的方法:
GET: 完整请求一个资源 (常用)
POST:提交表单 (常用)
HEAD: 仅请求响应首部
PUT: (webdav) 上传
DELETE:(webdav) 删除
OPTIONS:返回请求的资源所支持的方法的方法
TRACE: 追求一个资源请求中间所经过的代理
HTTP报文头部信息
Accept 就是告诉服务器端,我接受那些MIME类型
Accept-Encoding 这个看起来是接受那些压缩方式的文件
Accept-Lanague 告诉服务器能够发送哪些语言
Connection 告诉服务器支持keep-alive特性
Cookie 每次请求时都会携带上Cookie以方便服务器端识别是否是同一个客户端
Host 用来标识请求服务器上的那个虚拟主机,比如Nginx里面可以定义很多个虚拟主机
那这里就是用来标识要访问那个虚拟主机。
User-Agent 用户代理,一般情况是浏览器,也有其他类型,如:wget curl 搜索引擎的蜘蛛等
条件请求首部:
If-Modified-Since 是浏览器向服务器端询问某个资源文件如果自从什么时间修改过,那么重新发给我,这样就保证服务器端资源
文件更新时,浏览器再次去请求,而不是使用缓存中的文件
安全请求首部:
Authorization: 客户端提供给服务器的认证信息;
服务器端响应http请求,浏览器得到html代码
响应状态码
1xx: 信息性状态码
100, 101
2xx: 成功状态码
200:OK
3xx: 重定向状态码
301: 永久重定向, Location响应首部的值仍为当前URL,因此为隐藏重定向;
302: 临时重定向,显式重定向, Location响应首部的值为新的URL
304:Not Modified 未修改,比如本地缓存的资源文件和服务器上比较时,发现并没有修改,服务器返回一个304状态码,
告诉浏览器,你不用请求该资源,直接使用本地的资源即可。
4xx: 客户端错误状态码
404: Not Found 请求的URL资源并不存在
5xx: 服务器端错误状态码
500: Internal Server Error 服务器内部错误
502: Bad Gateway 前面代理服务器联系不到后端的服务器时出现
504:Gateway Timeout 这个是代理能联系到后端的服务器,但是后端的服务器在规定的时间内没有给代理服务器响应
浏览器解析html代码,并请求html代码中的资源
浏览器按顺序解析html文件,构建DOM树,在解析到外部的css和js文件时,向服务器发起请求下载资源,若是下载css文件,则解析器会在下载的同时继续解析后面的html来构建DOM树,则在下载js文件和执行它时,解析器会停止对html的解析。这便出现了js阻塞问题。
预加载器:
当浏览器被脚本文件阻塞时,预加载器(一个轻量级的解析器)会继续解析后面的html,寻找需要下载的资源。如果发现有需要下载的资源,预加载器在开始接收这些资源。预加载器只能检索HTML标签中的URL,无法检测到使用脚本添加的URL,这些资源要等脚本代码执行时才会获取。
注: 预解析并不改变Dom树,它将这个工作留给主解析过程
浏览器解析css,形成CSSOM树,当DOM树构建完成后,浏览器引擎通过DOM树和CSSOM树构造出渲染树。渲染树中包含可视节点的样式信息(不可见节点将不会被添加到渲染树中,如:head元素和display值为none的元素)
浏览器对页面进行渲染呈现给用户
最后,浏览器利用自己内部的工作机制,把请求到的静态资源和html代码进行渲染,渲染之后呈现给用户。