前言
- hello,大家好,我是 Lorin,今天这篇文章我将从浏览器搜索栏键入开始,分析整个流程中发生的重要事件,以及面试中涉及的常见面试题。
整体流程
- 上图展示了,从url键入开始到页面渲染完成的整体流程,接下来我们将一一分析每个阶段具体会发生了什么。
浏览器输入 url
- 当我们在浏览器导航栏输入内容时,浏览器会判断我们输入的内容是搜索文本还是符合规则的 url:
内容为搜索文本
- 若内容为搜索文本,浏览器调用默认的搜索引擎就行搜索。
内容为 url
- 若内容满足 url 规则,则将内容视为 url 进行访问,访问之前需要进行 HSTS 预检查。
HSTS 预检查
为什么需要 HSTS 预检查
- 现在大多数网站只通过 HTTPS 对外提供服务,但用户第一次访问时往往输入 www.example.com ,而不是 www.example.com ,那么整个访问流程就如下图所示:
- 这时候攻击者就会有机可乘,通过拦截第一次请求,从而进行后续的攻击,比如篡改数据、跳转到钓鱼网站等等。
HSTS 如何解决上述问题
- HSTS:HTTP Strict Transport Security (HTPP严格传输安全)是一种互联网安全策略机制,目的是让浏览器强制使用HTTPS与网站进行通信。用来减少会话劫持的风险。
- HSTS 核心响应头:Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload],它告诉浏览器当前一段时间只能通过HTTPS访问。
ini
例如:Strict-Transport-Security: max-age=31536000; includeSubDomains
max-age是必选参数,是一个以秒为单位的数值,它代表着HSTS Header的过期时间,通常设置为1年,即31536000秒。
includeSubDomains是可选参数,如果包含它,则意味着当前域名及其子域名均开启HSTS保护。
preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。
HSTS 存在的问题
-
细心的你可能会发现,HSTS存在一个比较薄弱的环节,如浏览器第一次访问或者没有域名HSTS信息,那么第一次请求仍然是不安全的,一般有两种解决方案:
1、现代浏览器内置的预加载HSTS。如果域名在内置HSTS列表中,则强制使用HTTPS。
2、将HSTS信息加入到域名系统记录中。但由于建设成本过高,目前还没有大规模部署。
baidu.com 和 www.baidu.com 区别
- 先说结论:www.baidu.com 是二级域名,baidu.com 是一级域名。
有何影响
- 虽然两个域名都可以解析到同一个IP上,对用户使用并没有影响,但是会让搜索引擎认为有两个相同的网站存在,造成重复收录,对SEO造成不好影响。
如何解决
- 301重定向。假设我们使用 www.baidu.com 为主域名,则将 baidu.com 重定向 www.baidu.com。
根据域名查询IP
- 当我们调用搜索引擎进行文本搜索或者访问某个 url 时,需要通过 DNS 查询获取域名的 IP 地址。
DNS 查询流程
- 浏览器缓存:浏览器会缓存DNS记录一段时间。有趣的是操作系统没有告知浏览器每条DNS记录的time-to-live,因此浏览器会以一个固定的时间长度来缓存这些DNS记录(每个浏览器之间不同,一般是2-30分钟)。
- 操作系统缓存:如果浏览器缓存没有找到,那么浏览器会调用系统查询。(Windows中是gethostbyname)。实际是从 host 文件中取,当然操作系统有自己的缓存。
- 路由器器缓存:继续查询路由器 DNS 缓存。
- ISP DNS:下一个要查询的就是服务提供商(电信网、移动网等)的DNS服务器。
DNS 迭代查询和递归查询
递归查询
- 客户端向本地域名服务器发送一次请求,本地域名服务器继续请求根域名服务器,返回主机对应的IP地址或报错,即无法解析域名。(类似代理的形式)
迭代查询
- 客户端发出一次域名查询请求,若域名服务器无法解答,则会返回一个可以解答的域名服务器地址,客户端再次请求返回的域名服务器地址,直达查询成功或返回错误。
- 通常迭代查询和递归查询结合使用,主机向本地名称服务器的查询一般采用迭代查询,而本地名称服务器向DNS(一级、二级、三级...)域名服务器采用递归查询
浏览器向服务发起HTTP请求
- 根据域名查询IP成功后,浏览器就可以向服务器发起 HTTP 请求, HTTP 是基于 TCP 协议,TCP 是面向连接的,因此需要先进行三次握手建立连接。
三次握手
流程分析
- 最开始客户端和服务端都处于 Closed 关闭状态,服务端监听端口等待建立连接。
- 客户端初始化序列号 client_sn,并将 SYN 置为 1,表示 SYN 报文;客户端将报文发送给服务端,请求建立连接。报文发送后,客户端处于 SYN_SENT 同步已发送状态。
- 服务端收到客户端建立连接请求后,初始化序列号 service_sn,并将应答序列号置为 client_sn + 1,同时将 SYN、ACK 置为 1,表示同步应答报文。报文发送后,服务端进入 SYN_RECVD 同步已收到状态。
- 客户端收到服务端回复后,将应答序列号置为 service_sn + 1,ACK 置为 1,表示为应答报文。报文发送后,客户端进入 ESTABLISHED 建立状态。
- 服务端收到客户端应答后进入 ESTABLISHED 建立状态。
问题
为什么需要3次握手,2次或4次行不行?
- 主要有以下三个原因:
- 原因一:避免历史重复连接造成混乱
vbnet
RFC 793 指出的 TCP 连接使用三次握手的首要原因:
The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
三次握手的首要原因是为了防止旧的重复连接初始化造成混乱。
大家可以想象以下场景:
客户端发送连接请求后宕机,然后不断重启建立连接,由于是重新建立连接(并不是重发),会生成新的序列号尝试建立连接。
如果是两次连接,每一次客户端重启发送的连接服务端都需要直接建立连接;
但三次连接需要客户端再次确认,当客户端发现是失效连接后,会发送 RST 报文到服务端让服务端释放连接。
-
原因二:同步双方初始化序列号
TCP 是需要保证的可靠的连接,序列号是保证可靠性的关键因素:
1、接收方可以去除重复的数据
2、接收方可以根据数据包的序列号按序接收
3、可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道) -
原因三:避免资源浪费
1、如果只有两次连接,收到客户端连接请求后就建立连接,上述原因一的场景下会建立较多的无效连接,造成资源浪费。
四次挥手
- 有三次挥手建立连接,那么就一起聊聊断开连接时候的四次挥手。
流程分析
- 最开始客户端和服务端都处于 ESTABLISHED 连接建立状态。
- 客户端准备断开连接,发送 FIN = 1 的报文给服务端,即 FIN 报文,发送成功后客户端进行 FIN_WAIT_1 状态。
- 服务端接受到客户端请求后,向客户端发送应答报文并进入 Close_WAIT 等待关闭状态。
- 当服务端数据全部发送完成后,服务端发送 FIN = 1 的报文给客户端,表示可以关闭请求,发送报文成功后进入 LAST_ACK 状态。
- 客户端端收到请求后,回复服务端 ACK ,进入 TIME_WAIT 状态并等到 2MSL 后进入 Closed 关闭状态(2MSL 内收到服务端重发 FIN 会重置等待时间)。
- 服务端收到客户端 ACK 报文后进入 Closed 关闭状态。
问题
为什么需要 4 次挥手?
- 客户端发送 FIN 时仅仅代表客户端不需要发送数据,但是服务端可能还需要发送数据,因此服务端收到客户端关闭请求后,先回复 ACK 应答报文给服务端,等服务端数据发送完毕后在发送 FIN 同意可以关闭连接。
MSL 的含义以及为什么需要等待 2MSL?
- MSL 表示报文在网络上生存的最大时间。
- 等待 2MSL 进入关闭状态表示至少允许报文丢失一次,比如客户端发送 ACK 报文在第一个 MSL 内丢失,服务端重发 FIN 报文,客户端可以在第二个 MSL 内收到并重置 2MSL 计时。
- 为什么不是 4MSL 或 8MSL?事实上网络丢包的概率很小,除非网络十分糟糕,忽略这种场景性价比更高。
发起 HTTP 请求
- 这个GET请求指明使用 HTTP 1.1 GET方法 获取的URL:facebook.com。浏览器标识自己(User-Agent标识头),并说明它将接受哪些类型的响应(Accept和Accept-Encoding标识头)。Connection标头要求服务器保持TCP连接打开以进一步请求。该请求还包含浏览器为此域提供的cookie。
GET和POST请求
- GET和POST,两者是HTTP协议中发送请求常用的方法。
http
示例:
GET /index.html?name=qiming.c&age=22 HTTP/1.1
Host: localhost
POST /index.html HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=qiming.c&age=22
- 注意:这里只是约定,并不属于HTTP规范,实际上我们可以在POST请求中url中写入参数,或者GET请求中的body携带参数
GET和POST请求的几个主要区别
参数长度
- HTTP 协议没有Body和 URL 的长度限制,对 URL 限制的大多是浏览器和服务器的原因
- IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持
安全
- POST 比 GET 安全,因为数据在地址栏上不可见,且GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- 然而,从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上都是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文,需要使用 HTTPS 加密保证安全。
数据包
- 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
- 对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok,并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次
服务器处理HTTP请求
- 服务器处理HTTP请求,并响应浏览器结果。
服务器响应HTTP请求
- facebook服务器返回给浏览器请求的响应。
- 服务器给出了一个301 Moved Permanently的响应来告知浏览器去访问www.facebook.com而不是http://facebook.c...
浏览器发起重定向请求
- 服务器处理请求并响应 HTML:
HTTP 响应码
1xx:代表请求已被接受,需要继续处理(临时响应)
- 100(客户端继续发送请求,这是临时响应):这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分。常用于POST大数据传输
2xx:代表请求已成功被服务器接收、理解、并接受
- 200:请求已成功,请求所希望的响应头或数据体将随此响应返回
- 206:一般用来做断点续传,或者是视频文件等大文件的加载
3xx:表示要完成请求,需要进一步操作。 常用来重定向
- 301:永久重定向会缓存。新域名替换旧域名,旧的域名不再使用时,用户访问旧域名时用301就重定向到新的域名
- 302:临时重定向不会缓存,常用 于未登陆的用户访问用户中心重定向到登录页面
- 304:协商缓存,告诉客户端有缓存,直接使用缓存中的数据,返回页面的只有头部信息,是没有内容部分
4xx:代表了客户端看起来可能发生了错误,妨碍了服务器的处理
- 400:参数有误,请求无法被服务器识别
- 403:告诉客户端进制访问该站点或者资源,如在外网环境下,然后访问只有内网IP才能访问的时候则返回
- 404:服务器找不到资源时,或者服务器拒绝请求又不想说明理由时
5xx:表示服务器无法完成明显有效的请求。服务器处理异常
- 503:服务器停机维护时,主动用503响应请求或 nginx 设置限速,超过限速,会返回503(通常表示服务器处理异常)
- 504:网关超时。表示上游服务器处理请求的时间太长,超过了网关或代理的等待时间。
浏览器处理服务器响应
- 当浏览器收到服务器的响应后会进行渲染以及进一步请求。
浏览器渲染HTML
- 当浏览器收到 HTML 响应后就开始渲染整个页面:
发送嵌入对象请求
- 当浏览器渲染HTML时,它会注意到需要获取其他URL的标记。浏览器将发送GET请求以检索每个文件,比如 image、css、js 文件。
bash
Images:
http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif
http://static.ak.fbcdn.net/rsrc.php/zBS5C/hash/7hwy7at6.gif
CSS style sheets:
http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css
http://static.ak.fbcdn.net/rsrc.php/zANE1/hash/cvtutcee.css
这些URL每个都将经历与 url 访问类似的过程。
进一步发送AJAX异步请求
- 即使在页面渲染完成之后,浏览器客户端仍然可能和服务端保持继续通信,比如获取最新的列表、聊天信息等等,浏览器执行的JavaScript使用GET或POST请求向服务器发送异步请求,我们通常称为"AJAX"。
- 但HTTP是请求-响应模式,一次请求一次连接,对于一些聊天等需要频繁消息通信的场景我们一般会使用长连接等方式进行性能优化。
总结
- 本篇文章从浏览器搜索栏键入 url 开始,到最后页面渲染完成,分析其中的一些关键环节以及面试常考问题,希望对你有帮助。
参考
个人简介
👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.
🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。
🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。
💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。
🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。
📖 保持关注我的博客,让我们共同追求技术卓越。