一、前言
文章为了加深自我理解,参考:
前端经典面试题: 从输入URL到页面加载发生了什么?
老生常谈-从输入url到页面展示到底发生了什么
HTTP 请求头与请求体
四种常见的POST提交方式
二、开始
从用户开始输入 url 到用户见到页面内容,过程如下:
- 输入 url
- 查找 ip ,从本地系统查找 hosts 文件,是否有 ip ? 有则下一步 : 没有,进行 DNS 解析
- TCP 连接
- 发送 HTTP 请求
- 服务器处理并返回 HTTP 请求
- 浏览器解析渲染页面
- 用户看到完整页面
三、具体过程
I. 输入 url
用户在浏览器中输入网址的时候,浏览器就只能的会从历史记录、书签来搜索你当前输入的地址,如果你访问的是有缓存过的地址,网页可能直接展示出来。
II. 查找 ip
每个域名都是对应有一个 ip 地址, 诸如 www.baidu.com 这些名称只是用来方便用户记忆。所以在获取网页内容之前,浏览器得先知道这个网址的 ip 地址,才能去到对应的服务器去获取资源。
首先,浏览器会尝试在本地的 hosts 文件中去查看是否有相应的 ip 记录,有的话就直接用对应的 ip ,省去 DNS 解析。
DNS 解析
DNS (Domain Name System ,域名系统)解析,就是一个网址到 ip 地址转换的过程,解析是一个递归查询的过程。
经过多次的服务器往返后,得到了对应的 ip 地址。从上述过程中,可以看出网址的解析是一个从右向左的过程,浏览器首先会去访问
本地DNS服务器
,查看是否有缓存 ip ,没有,那么去访问根服务器
,每个网址的真正地址是www.baidu.com.
,就是在网址后还有一个点,这个点就是指向根服务器
,然后根服务器
告诉你,你应该去问COM顶级域名服务器
,然后COM顶级域名服务器
又告诉你,你应该去问baidu.com服务器
,这下终于找到负责人了,baidu.com服务器
就会把它管理的www.baidu.com
的 ip 地址返回告诉浏览器,费了这么大劲,浏览器终于如愿以偿拿到 ip 了,接下来就可以向该 ip 拿页面了。
问题是,如果每一次浏览器访问个网站都要这么费劲,那用户体验不就很差?所以聪明的浏览器在访问过一次之后,会去缓存下这个网址对应的 ip 地址,下次就能直接用了。另外,聪明的本地DNS服务器
、所有的服务器也会存下映射关系,以便下次使用。另外,也可以人为修改 Hosts 文件来指定网址的 ip 映射关系。
III. 建立 TCP 连接
浏览器在拿到 ip 地址之后,就开始准备 HTTP 请求了,但首先要先和服务器建立连接通道,这时候就用到 TCP 建立三次握手了。 TCP 协议是用来建立对话通道的,在客户端和服务器还没对接之前,是无法确定各种各样的请求的,举个网络上看到的例子:
- 甲: “喂!是乙吗?”
- 乙: “是呀,我是乙。”
- 甲: “那我们开始对话吧!”
只有确保的请求服务器正确,才可以真正开始请求。另外,在请求头会有一个
Connection: keep-alive
,表示保持 TCP 连接,这样客户端在下次请求的时候,就不需要重新建立 TCP 连接了,虽然这样会损耗部分服务器性能,但对双方(客户端、服务器)也都是有好处的。
IV. 发起 HTTP 请求
典型的 HTTP 请求消息头域,如下:
POST/GET http://download.microtool.de:80/somedata.exe
Host: download.microtool.de
Accept:*/*
Pragma: no-cache
Cache-Control: no-cache
Referer: http://download.microtool.de/
User-Agent:Mozilla/4.04[en](Win95;I;Nav)
Range:bytes=554554-
总的来说 HTTP 请求包含三部分:请求行、请求头、请求体(请求正文)。
a. 请求行
请求行分为三部分:请求方法、请求地址和协及版本。
HTTP/1.1定义的请求方法有 8 种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常用的两种 GET 和 POST。以下为 GET 和 POST 区别的文章:
GET VS POST
注意: 在 POST、PUT、PATCH 三个请求中会包含请求体,其他的并没有。
b. 请求头
请求头的详细类型和内容的详细内容谷歌搜索,一下是一次请求的样例:
c. 请求体
请求体主要是用来存放数据,数据类型存储在 Content-Type 响应头上,接触过的有:
-
application/x-www-form-urlencoded
最常见的 POST 提交数据方式,浏览器原生<form>
表单,格式如下
POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3
-
application/json
主要用来提交 JSON 格式的数据,格式为:
POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8
{"title":"test","sub":[1,2,3]}
-
multipart/form-data
使用表单上传文件时的格式,用于上传文件,格式如:
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
-
text/xml
传输数据,没用过,不清楚,格式如下:
POST http://www.example.com HTTP/1.1
Content-Type: text/xml
<?xml version="1.0"?>
<methodCall>
<methodName>examples.getStateName</methodName>
<params>
<param>
<value><i4>41</i4></value>
</param>
</params>
</methodCall>
V. 服务器处理请求并返回 HTTP 报文
HTTP 请求也是三部分请求:状态码、相应头、响应体(响应报文)。
a. 状态码
状态码由3位数组成,第一个数字定义了相应类别,共有五种可能取值:
- 1XX 消息:代表请求已被接受,需要继续处理。这类响应是临时响应,通常情况下,服务器是不会给客户端发送1xx响应。
- 2XX 成功:代表请求成功被服务器接收、理解、接受。
- 3XX 重定向:代表客户端需要采取进一步的操作才能完成请求。
- 4XX 客户端错误:代表客户端看起来发生了错误,妨碍了服务器的处理。
- 5XX 服务器错误:表示服务器无法完成明显有效的请求。
参考: HTTP 状态码
b. 响应头
涉及到服务器名称、缓存、响应体类型等,详细内容自行谷歌。
c. 响应体
响应体除了有 JSON 数据等一些其他数据类型外,也是获取 HTML、CSS、JS、图片等文件的地方。
HTTP 和 HTTPS
HTTPS 是 HTTP 请求前,客户端与服务器先进行一次握手(TLS/SSL握手),用于数据加密,具体加密我不懂,参考这里:图解SSL/TLS协议。很明显的是,虽然 HTTPS 更为安全,但与 HTTP 相比,多了一次连接,肯定会影响一部分的加载速度。一张图说明:
VI. 浏览器解析渲染页面
浏览器解析服务器返回的 HTML 时,是从上往下顺序解析的,遇到 CSS link、JS link 就会向服务器请求该资源,浏览器也开始生成 DOM 结构,但需要注意的是,CSS 文件不会阻塞 DOM 结构的生成,而 JS 文件会(因为 JS 可以操作 DOM),所以如果在 HTML 头部开始解析 JS 的话,浏览器会等 JS 请求完并且初始化结束才会继续生成 DOM 结构。这也是为什么 JS 经常放在
<body>
最后,而且用的是window.onload=function(){}
。不过可以在<script async></script>
加个async
,告诉浏览器不用等我 JS 啦,赶紧开始生成你的 DOM 树结构(async是异步加载的意思)。
DOM 树生成后,就要上色,这时候就是 CSS 的作用了。一张图说明:
另外,这里有个视频很好的讲解了浏览器对网页的处理:网站性能优化(中/英)
VII. 用户看到完整页面
到此,用户终于能完整的看到一个页面了,没想到吧,在这么短短2秒,浏览器做了这么多事,还跑了这么远,不容易。要学的内容还很多,这是一篇前端新手的理解,参考很多东西,如有出错,请严厉指出~