当用户在浏览器的地址栏中输入 URL 并点击回车后,页面是如何呈现的。
简略来说,当用户在浏览器的地址栏中输入 URL 并点击回车后,浏览器从服务端获取资源,然后将内容显示在页面上。这个过程通过了:浏览器缓存 -> DNS 域名解析 -> URL 编码 -> 运用 HTTP 或许运用 HTTPS 协议发送恳求 ->
- 关于拜访静态资源的 HTTP 恳求:CDN -> CDN 回源到目标存储 OSS 或许源服务器
- 关于拜访动态资源的 HTTP 恳求:负载均衡器 Nginx -> 应用服务器【API 网关(Zuul、GateWay 等)-> 内部服务(微服务,Controller、Service、DAO)】-> 缓存体系(Redis、EhCache 等) -> 存储体系(MySQL、PostgreSQL、MongoDB 等)
为了削减呼应时间,整个过程中的几乎每一个环节都会有缓存。
为了提高体系的可用性、功能,整个过程中的许多环节都需求部署多节点。
浏览器
当用户在浏览器的地址栏中输入 URL 并点击回车后,首要由浏览器进行处理。
浏览器缓存
当用户在浏览器的地址栏中输入 URL 并点击回车后,浏览器会查看自己是否缓存了该资源。
- 假如浏览器缓存了该资源,并且缓存未过期,那么直接从缓存中获取资源,不向服务端发送恳求(命中强缓存)。
- 假如浏览器缓存了该资源,但是缓存已通过期了,那么浏览器向服务端发送条件恳求。服务端会依据条件恳求首部字段(If-Match、If-Modified-Since 等)来判别是否命中洽谈缓存。
- 假如命中了洽谈缓存,那么服务端会回来 304 状况码(Not Modified),而不回来浏览器恳求的资源。告知浏览器能够直接用浏览器缓存中的资源。
- 假如没有命中洽谈缓存,那么服务器回来浏览器恳求的资源。
DNS 域名解析
当用户在浏览器的地址栏中输入 URL 并点击回车后,浏览器要判别 URL 中的是 IP 地址,还是域名。假如 URL 中的是域名,那么首要要做的就是域名解析。
域名解析的过程:首要是浏览器查看浏览器的缓存。假如浏览器中没有该域名的缓存,那么浏览器询问【本地 DNS 解析器】,【本地 DNS 解析器】首要查看本地 DNS 缓存。假如本地 DNS 缓存中没有该域名的缓存,那么【本地 DNS 解析器】恳求【本地 DNS 服务器】进行域名解析。假如【本地 DNS 服务器】中没有该域名的缓存,那么【本地 DNS 服务器】向 DNS 体系中的其他长途 DNS 服务器发送查询恳求。
- 假如域名解析失利,浏览器会展示一个报错页面,提示域名不存在。
- 假如域名解析成功,浏览器就获取到一个域名对应的 IP 地址。
以【本地 DNS 解析器】恳求【本地 DNS 服务器】进行 www.CDNbook.com 域名的解析为例:
(1)【本地 DNS 解析器】向【本地 DNS 服务器】发送域名解析恳求。(8)【本地 DNS 解析器】收到来自【本地 DNS 服务器】的应对。
(2)【本地 DNS 服务器】向【根 DNS 服务器】发送域名解析恳求,【根 DNS 服务器】回来 .com 顶级域的域名服务器列表(多条 NS 记载)。
(4)【本地 DNS 服务器】收到应对后,在 .com 顶级域的域名服务器列表中选择一个 IP 地址,向这个 IP 地址对应的 DNS 服务器发送域名解析恳求,.com 顶级域的域名服务器回来 CDNbook.com 域的域名服务器列表。
(6)【本地 DNS 服务器】收到应对后,在 CDNbook.com 域的域名服务器列表中选择一个 IP 地址,向这个 IP 地址对应的 DNS 服务器发送域名解析恳求,CDNbook.com 域的域名服务器回来 www.CDNbook.com 域的 A 记载列表(多个 IP 地址)。
(8)【本地 DNS 服务器】收到应对后,在 www.CDNbook.com 域的 A 记载列表中选择一个 IP 地址,将该 IP 地址回来给【本地 DNS 解析器】。
(9)浏览器获取到域名对应的 IP 地址,这个 IP 地址可能是 CDN 服务器的 IP 地址,也可能是源服务器的 IP 地址。无论是什么服务器的 IP 地址,浏览器都会向这个服务器发送恳求,服务器将用户恳求的内容回来给浏览器。
URL 编码
URL 编码也被称为百分号编码。
URL 编码的作用是:在 URL 中,运用 “安全的字符”(允许呈现的字符、无歧义的字符) 替换 “不安全的字符”(不允许呈现的字符、有歧义的字符)
- 将 “非 ASCII 字符” 编码为 “ASCII 字符”,便于在 URL 中传输非 ASCII 字符。(URL 中只能呈现 ASCII 字符,不能呈现非 ASCII 字符)
- 将 “空格” 编码为 “%20”,便于在 URL 中传输空格。(URL 中不能呈现空格)
- 将 “没有表明特别意义的保存字符” 进行 URL 编码。(URL 中多个查询参数之间用 & 符号分隔。假如参数值中包含了 & 字符,那么会对 URL 解析造成影响,因此需求对造成歧义的 & 符号进行编码)
URL 编码的规则:简略来说,假如需求对一个字符进行 URL 编码,首要需求判别该字符是否是 ASCII 字符:
-
假如一个字符是 ASCII 字符,那么对该字符进行 URL 编码,首要需求把该字符的 ASCII 的值表明为两个 16 进制的数字,然后在其前面放置转义字符 %,就得到了该字符的 URL 编码成果。
-
假如一个字符是非 ASCII 字符,那么对该字符进行 URL 编码,首要需求运用指定的字符编码方法(主张运用 UTF-8 字符编码),将 “非 ASCII 字符” 编码为字节序列(字节序列即二进制数据);然后对其字节序列进行 URL 编码。URL 编码 “二进制数据”,首要需求把 “二进制数据” 表明为 8 位组的序列,将每个 8 位组表明为两个 16 进制的数字,然后在其前面放置转义字符 %,就得到了 “二进制数据” 的 URL 编码成果。
HTTPS 通讯
浏览器运用 HTTP 或许运用 HTTPS 协议和服务器通讯。
运用 HTTPS 协议通讯,通讯的两边会先树立 TCP 衔接,然后履行 TLS 握手,之后就能够在安全的通讯环境里发送 HTTP 报文了。
TCP 握手
一开始,客户端和服务端都处于 close 状况。
先是服务端监听某个端口,此刻服务端处于 listen 状况。
这个时分客户端就能够发送衔接恳求报文了。
第一次握手
客户端会自动发送衔接恳求报文,随机初始化序列号为 x,并把 SYN 标志位设置为 1,表明 SYN 报文。
客户端发送 SYN 报文后,客户端进入 syn_sent 状况。
第二次握手
服务端收到 SYN 报文后,服务端会发送 SYN-ACK 报文,用于对客户端发送的 SYN 报文进行应对。
服务端会随机初始化序列号为 y,承认序列号设置为 x + 1,并把 SYN 标志位、ACK 标志位设置为 1。
服务端发送 SYN-ACK 报文后,服务端进入 syn_receive 状况。
第三次握手
客户端收到 SYN-ACK 报文后,客户端会发送 ACK 报文,用于对服务端发送的报文进行应对。
客户端会将序列号设置为 x + 1,承认序列号设置为 y + 1,ACK 标志位设置为 1。
客户端发送 ACK 报文后,客户端处于 established 状况。
当服务端收到 ACK 报文后,服务端进入 established 状况。
此刻 TCP 衔接就树立完结了,客户端和服务端就能够相互发送数据了。
TLS 握手
TLS 握手过程的简要描述:通讯的两边在 TLS 握手的过程中洽谈 TLS 的版本号、暗码套件,交流随机数、数字证书和密钥参数,最终通讯的两边洽谈得到会话密钥。(”Hello” 音讯交流随机数,”Key Exchange” 音讯交流 “Pre Master Secret”)
- 浏览器给服务器发送 “Client Hello” 音讯,服务器给浏览器发送 “Server Hello” 音讯。通讯的两边洽谈 TLS 的版本号、暗码套件,并交流随机数。
- 交流数字证书:服务器为了向浏览器证明自己的身份,服务器给浏览器发送 “server Certificate” 音讯,以发送数字证书链,其中包含了两个证书。一个是 CA 组织颁布的数字证书,另一个是 CA 组织的数字证书。
- 服务器给浏览器发送 “Server Key Exchange” 音讯,浏览器给服务器发送 “Client Key Exchange” 音讯。通讯的两边交流密钥参数(Client Params 和 Server Params),然后通讯的两边就用 ECDHE 算法算出 “Pre Master Secret”。
- 通讯的两边依据自己已知的参数(Client Random、Server Random 和 Pre Master Secret)算出主密钥 “Master Secret”,并运用主密钥拓展出更多的密钥(会话密钥),避免只用一个密钥带来的安全隐患。
- 浏览器给服务器发送 “Change Cipher Spec” 音讯,服务器也给浏览器发送 “Change Cipher Spec” 音讯。告知对方:后续传输的都是对称密钥加密的密文。
- 浏览器给服务器发送 “Finished” 音讯,服务器也给浏览器发送 “Finished” 音讯。通讯的两边把之前发送的数据做个摘要,再用对称密钥加密一下,让对方做个验证。
- 两边都验证成功,握手正式结束,之后就能够正常收发被加密的 HTTP 恳求和呼应了。
TCP / IP 模型的通讯
发送数据包
当用户在浏览器的地址栏中输入 URL 并点击回车后,首要由浏览器进行处理,这些处理相当于应用层功能。浏览器处理完结今后,浏览器依据 HTTP 标准构建报文,并将 HTTP 报文发送给传输层的 TCP。
TCP 模块的处理:TCP 依据浏览器的指示,担任树立衔接、发送数据以及断开衔接。TCP 在浏览器发送过来的数据前端再加上自己的 TCP 首部,随后将附加了 TCP 首部的包再发送给网络层的 IP。
IP 模块的处理:IP 将 TCP 传过来的 TCP 首部和 TCP 数据合起来当做自己的数据,并在 TCP 首部的前端再加上自己的 IP 首部。IP 包生成后,参阅路由操控表决定接受此 IP 包的路由器 或 主机。随后,IP 包将被发送给衔接这些路由器 或 主机网络接口的驱动程序,以完成真实的发送数据。
假如尚不知道接纳端的物理地址(MAC 地址),能够利用 ARP(Address Resolution Protocol) 通过 IP 地址查找物理地址(MAC地址)。
只要知道了对端的物理地址(MAC 地址),就能够将 MAC 地址和 IP 地址交给以太网的驱动程序,以完成真实的发送数据。
网络接口(以太网驱动) 的处理:以太网的驱动程序将 IP 传过来的 IP 首部和 IP 数据合起来当做自己的数据,并在 IP 首部的前端再加上自己的以太网首部。以太网数据包将通过物理层传输给接纳端。
接纳数据包
网络接口(以太网驱动) 的处理:主机收到以太网包今后,首要从以太网的包首部找到物理地址(MAC 地址)。主机依据物理地址(MAC 地址),判别是否为发给自己的包。
- 假如接纳到的不是发给自己的包,那么主机丢掉数据。
- 假如接纳到的恰好是发给自己的包,那么主机接纳数据并查找以太网包首部中的类型域(类型域记载上一层的协议类型),然后确定将数据传给哪个处理程序。
- 假如上一层协议是 IP,那么就将数据传给处理 IP 的程序;
- 假如上一层协议是 ARP,那么就将数据传给处理 ARP 的程序;
- 假如以太网包首部的类型域包含了一个无法辨认的协议类型,那么主机丢掉数据。
IP 模块的处理:IP 模块收到 IP 包首部及后边的数据部分今后,也做和以太网驱动类似的处理。
- 假如判别得出包首部中的 IP 地址与自己的 IP 地址匹配,那么就接纳数据并查找 IP 包首部中的类型域(类型域记载上一层的协议类型),然后确定将数据传给哪个处理程序。
- 假如上一层协议是 TCP,那么就将数据传给处理 TCP 的程序;
- 假如上一层协议是 UDP,那么就将数据传给处理 UDP 的程序。
关于有路由器的情况下,接纳端的 IP 地址往往不是自己的 IP 地址,此刻需求借助路由操控表,在查找到应该送达的主机 或 路由器今后再转发数据。
TCP 模块的处理:TCP 模块收到 TCP 包首部及后边的数据部分今后,首要会计算一下校验和,判别数据是否被损坏。然后查看是否在依照序号接纳数据。最终查看端口号,然后确定将数据传给哪个详细的应用程序。
TCP 模块接纳数据结束后,接纳端给发送端发送一个 “承认(ACK)”。假如发送端没有收到这个承认信息,那么发送端会认为接纳端没有接纳到数据,然后发送端会一直重复发送。
数据被完整地接纳今后,会传给由端口号辨认的应用程序。
应用程序的处理:接纳端应用程序会直接接纳发送端发送的数据。服务器准备好发送端应用程序所需的数据今后,以相同的方法将数据发送到发送端应用程序。
服务端
当浏览器的恳求到达服务端之后,恳求首要通过 Linux 虚拟服务器 LVS,调度器将网络恳求分发到 Nginx 上。
- 假如 Nginx 上缓存的有用户恳求的内容,那么 Nginx 直接将用户恳求的内容发送给浏览器。
- 假如 Nginx 上没有缓存用户恳求的内容,那么 Nginx 拜访应用服务器(Web 服务器,比方 Java 的 Tomcat / Netty / Jetty,Python 的 Django)获取资源,再将用户恳求的内容回来给浏览器。Nginx 会依据缓存战略缓存从应用服务器获取到的资源,浏览器也会依据缓存战略缓存收到的内容。
Nginx 也能够直接拜访缓存体系测验获取资源(Varnish 缓存静态资源,Redis 缓存动态资源)。假如缓存体系中没有用户恳求的内容,再拜访应用服务器获取资源。
当 Nginx 的恳求到达应用服务器之后,恳求首要通过 API 网关。API 网关依据路由规则,将外部拜访网关地址的流量路由到内部服务集群中正确的服务节点上。网关还能够依据需求作为流量过滤器来运用,供给某些额外的可选的功能,例如:
- 流量治理:流量操控、服务容错(限流、降级、熔断)
- 安全防护、拜访操控:防刷操控、防爬虫、是非名单、认证、授权、数据完整性校验、数据加密
- 监控:功能监控、日志监控
- 其他:协议适配转化、缓存
外部拜访网关地址的流量被路由到内部服务集群中正确的服务节点上之后,服务节点会再拜访缓存体系(比方 Redis、EhCache 等),存储体系(比方 MySQL、PostgreSQL、MongoDB 等)完成业务操作,获取资源。
服务节点将获取到的资源回来给 API 网关,API 网关将资源回来给 Nginx,Nginx 再将用户恳求的内容回来给客户端,客户端依据 HTTP 规则解析报文,并将用户恳求的内容显示在页面上。
参阅资料
08 | 键入网址再按下回车,后边究竟发生了什么? (geekbang.org)
域名 – 真实的飞鱼 – 博客园 (cnblogs.com)
URL编码 – 真实的飞鱼 – 博客园 (cnblogs.com)
计算机网络 | TCP 衔接的树立 和 TCP 衔接的断开 – 真实的飞鱼 – 博客园 (cnblogs.com)
《图解TCP / IP》