访问一个https协议的网站背后的故事

或许我们知道访问一个网站背后大概发生了什么,比如DNS解析、TLS连接建立、路由、服务器响应、浏览器解析超文本数据等等,但是要是详细的说明以下的话还是不能够理得很清楚,因此整理记录一下备忘

应用层

浏览器输入URL

比如在浏览器地址栏输入https://chujian521.github.io/about/#%E4%B8%BA%E4%BB%80%E4%B9%88%E5%86%99Blog%EF%BC%9F,浏览器会解析URL并开始网络请求。URL一般包括以下部分:

  • protocol:使用的协议,这里是https
  • host:主机名,这里是chujian521.github.io
  • port:端口号,一般https的默认端口号为443
  • path:请求资源路径,这里示例的path为 about/
  • query:查询参数,这里为空,一般出现的在path之后的 ?k=v
  • fragment: 主要是用来标识资源里的某个资源,比如例子里的 #后面的部分

DNS解析主机名

DNS(Domain Name Service)就是一种将网站主机名转换成网络世界的ip地址的一种服务,人类容易记住有含义的名字,但是在网络中路由器使用的是固定化结构的IP地址,因此人就设计了这种主机名到IP地址的映射服务。

DNS的解析大概有以下过程:

  • 浏览器检查自身缓存,查找是否解析过这个域名,如果有使用缓存,解析结束,如果没有进入下一步
  • 检查操作系统的域名缓存,比如hosts文件中用户自定义的一些解析规则,如果有浏览器就会使用,没有进入下一步
  • 请求本地域名服务器解析,大部分网站在这里已经被解析,如果没有进入下一步
  • 本地域名服务器请求根域名服务器,根域名返回一个查询域的主域名服务器(.com, .cn, .org等),本地域名服务器根据查询到的主域名服务器向主域名服务器发送查询请求,主域名服务器查询域名对应的网站注册域名服务器,找到对应IP地址,返回给本地域名服务器,本地域名服务器缓存这个域名对应的ip,然后把解析结果返回用户。

DNS请求和回答报文的下层都是使用UDP数据报经过53端口发送的。

生成HTTP报文

客户端请求报文

基础结构:

  • 请求行:请求方法 请求资源地址 HTTP版本 CRLF换行符,示例 GET /about/ HTTP1.1 \r\n
  • 请求头:key: value CRLF换行符
  • 空行,标识请求头结束
  • 请求主体:即请求正文,POST会使用,GET方式没有这部分

请求头:

  • Accept:可接受的响应内容类型
  • Accept-Charset:可接受的字符集
  • Accept-Encoding:可接受的响应内容编码方式
  • Accept-Language:可接受的响应内容语言列表
  • Authorization:用于表示HTTP协议中需要认证资源的认证信息(Basic认证是不安全的)
  • Cache-Control:用来指定当前的请求/回复中的,是否使用缓存机制
  • Connection:客户端(浏览器)想要优先使用的连接类型
  • Cookie:由之前服务器通过Set-Cookie设置的(或者客户端产生的Cookie)一个HTTP协议Cookie
  • Content-Length:十进制数字表示的八位字节的数字长度的请求体
  • Content-Type:请求体的MIME类型 (用于POST和PUT请求中)
  • Origin:会在跨域请求时带上,服务端据此判断是否允许跨域
  • Referer:表示浏览器所访问的前一个页面,可以认为是之前访问页面的链接将浏览器带到了当前页面
  • User-Agent:浏览器的身份标识字符串
  • X-Forwarded-For:用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段

服务器响应报文

基础结构:

  • 响应行:HTTP版本 状态码 状态码文本描述 CRLF换行符,示例HTTP 200 OK
  • 响应头:key: value CRLF换行符
  • 空行,标识响应头结束
  • 响应主体

响应头:

  • Access-Control-Allow-Origin:指定哪些网站可以跨域源资源共享
  • Allow:对于特定资源的有效动作
  • Cache-Control: 通知从服务器到客户端内的所有缓存机制,表示它们是否可以缓存这个对象及缓存有效时间。其单位为秒
  • Connection:针对该连接的预期
  • Content-Encoding:响应资源所使用的编码类型
  • Content-Language:响应使用的语言
  • Content-Length:响应消息体的长度,十进制数字表示的八位字节的数字
  • Date:消息被发送的时间
  • ETag:对于某个资源的某个特定版本的一个标识符,通常是一个消息散列
  • Expires:响应过期时间
  • Location:用于在进行重定向
  • Refresh:用于重定向,默认5秒后刷新重定向
  • Server:服务器名称
  • Set-Cookie:设置http cookie
  • Status:响应状态
  • Vary:告知下游的代理服务器,应当如何对以后的请求协议头进行匹配,以决定是否可使用已缓存的响应内容而不是重新从原服务器请求新的内容
  • x-xss-protection:当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面

HTTP消息头支持自定义, 自定义的专用消息头一般会添加'X-'前缀。

http常见响应状态:

  • 200 请求成功
  • 206 Partial Content 服务器已经处理了部分GET请求,可用来实现断点续传或大文档分解为多个段下载
  • 301 永久重定向,请求的资源已经永久移动到新的位置
  • 302 临时重定向,请求资源临时从不同的URI响应请求
  • 304 未修改,GET请求资源未改变
  • 400 错误的请求,请求语义或者参数有误
  • 401 未授权,当前请求需要用户验证
  • 403 禁止访问,服务器理解请求,但是拒绝执行
  • 404 未找到,请求的资源未在服务器发现
  • 405 方法不被允许,请求中指定的方法不能用于请求相应的资源
  • 500 服务器错误,无法完成对请求的处理
  • 502 无效网关,作为网关或者代理服务器尝试执行请求时,从上游服务器接收到无效的响应
  • 503 服务不可达,由于临时的服务器维护或者过载,服务器当前无法处理请求
  • 504 网关超时,网关或者代理服务器执行请求时未能及时从上游服务器收到响应

HTTP 1.0/1.1/2.0版本有什么不同?

HTTP1.0默认使用 Connection:close,浏览器每次请求都需要与服务器建立一个 TCP 连接,服务器处理完成后立即断开 TCP 连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。

HTTP1.1默认使用 Connection:keep-alive长连接),避免了连接建立和释放的开销;通过 Content-Length 字段来判断当前请求的数据是否已经全部接受;HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的,并且有上上限限制;支持断点续传;共用TCP连接,但是请求是串行的,第二个请求只有子啊第一个请求结束后才能发送。

HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。HTTP2.0引入了server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前,免得客户端再次创建连接发送请求到服务器端获取。这样客户端可以直接从本地加载这些资源,不用再通过网络。

HTTP3.0的底层支撑协议QUIC基于UDP实现,又含TCP的特点,实现了又快又可靠的协议。

传输层

TLS加密

TLS可以提供数据的完整性和保密性,最常用的TLS1.2协商过程如下:

  • ClientHello,客户端表示想跟服务端安全进行通信,生成随机数R1和自己支持的加密算法发送给服务器
  • ServerHello,服务器收到,生成随机数R2,选择一种双方支持的加密算法,并返回给客户端自己的证书、随机数R2、会话密钥生成算法。
  • Certificate Verify:客户端验证证书的真实性,如果有误发出警告并断开链接,如果无误客户端就会生成随机数R3,根据会话秘钥算法使用R1、R2、R3生成会话秘钥,用服务器证书公钥加密随机数R3并发送给服务端。
  • Server Finish:服务器用私钥解密客户端发过来的随机数R3,根据会话秘钥算法使用R1、R2、R3生成会话秘钥,后面就可以使用会话密钥进行数据安全传输。

为什么要使用三个随机数呢?

  1. 增强伪随机数的随机性
  2. 防止报文被重放

为什么要发送一个Finish报文?

  1. 校验双方的身份,双方可以验证彼此是否为即将进行通信的对象

TCP连接建立解除

三次握手(建立连接)

第一次握手:客户端给服务端发一个 SYN 报文和初始序列号,此时客户端处于 SYN_Send状态。

第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号,同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD的状态

第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的初始化序列号 + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised状态。服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了连接。

四次挥手(释放连接,访问结束后)

第一次挥手:客户端发送一个FIN,用来关闭客户到服务器的数据传送。

第二次挥手:服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

第三次挥手:服务器关闭与客户端的连接,发送一个FIN给客户端。

第四次挥手:客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

数据传输

建立连接后数据传输就会通过传输层进行分包传输,TCP拥有流量控制和拥塞控制。采用滑动窗口机制实现流量控制,采用慢启动、拥塞避免、快重传、快恢复等机制实现拥塞控制。

网络层

NAT网络地址转换

工作原理

NAT技术可以让在专用网内拥有本地IP的主机通过装有NAT软件的路由器连接到因特网上能和外界通信的技术,借助于NAT技术,私有(保留)IP地址的”内部”网络通过路由器发送数据包时,私有地址被转换成合法的公有IP地址,而一个局域网只需使用少量公有IP地址(甚至是1个)即可实现私有地址网络内所有计算机与Internet的通信需求。

实现方式

  1. 静态转换Static NAT:私有IP转公有IP,IP地址一对一,即某一私有IP只能转为某一公有IP。

  2. 动态转换Dynamic NAT:私有IP转公有IP,转换的公有IP地址不确定。

  3. 端口多路复用OverLoad:所有内部网络的主机均可共享一个合法外部IP地址实现对Internet的访问。不仅可以最大限度地节约IP地址资源,同时,又可隐藏网络内部的所有主机,有效避免来自internet的攻击。

IP寻址

网络层负责把传输层封装的数据包在路由器之间传输,最终到达目的地址,根据目的地址IP就需要查找下一跳路由的地址。

查找过程如下:

  • 根据目的地址,判断是否处于同一内网,如果处于同一内网直接发送
  • 如果不是,查询路由表,找到路由,如果找不到明确的路由,就将数据传送给默认网关地址。
  • 路由器收到数据后,它再次为远程主机或网络查询路由,若还未找到路由,该数据包将发送到该路由器的缺省网关地址。而数据包中包含一个最大路由跳数(RIP路由协议),如果超过这个跳数,就会丢弃数据包,这样可以防止无限传递。路由器收到数据包后,只会查看网络层的封包数据。
  • 如果上面的步骤无法完成,那么该数据就无法传送,会向生成数据报文的应用程序返回一个网络不可达的错误信息。

ARP协议

ARP协议是将IP地址映射成硬件设备的MAC地址的。

寻找过程:

  • 发送源MAC地址为全FF的广播报文,此时广播域内所有设备都能收到这个请求。
  • 对应要查找的IP的设备收到报文之后,将发送者MAC地址缓存之后回复发送者自己的MAC地址。

数据链路层

MAC寻址

首先通过广播获取足够的MAC地址表,交换机使用MAC地址通过指向相应端口的交换结构将网络通信转向目的节点。交换机为了知道要使用哪个端口来传送单播帧,它必须首先知道自己的每个端口上都存在哪些节点。

交换机使用其 MAC 地址表来确定如何处理传入的数据帧。通过记录与其每一个端口相连的节点的 MAC 地址来构建其 MAC 地址表。当某个特定端口上的某个特定节点的 MAC 地址记录到地址表之后,交换机就可以知道在后续传输中,应将目的地为该特定节点的流量从与该节点对应的端口上发出。

当交换机收到传入的数据帧,而地址表中没有该帧的目的MAC地址时,交换机将把该帧从除接收该帧的端口之外的所有端口转发出去。当目的节点响应时,交换机从响应帧的源地址字段中获得的该节点的MAC地址,并将其记录在地址表中。

物理层

通过光纤等物理设备传输网络信号。

服务器收到请求

反向代理服务器

大型的网站都有负载均衡,流量到达反向代理服务器之后,由反向代理服务器执行调度算法,分配给不同的服务器处理请求。

服务器经过层层解封装,最终会得到原始的http请求。

服务器处理请求

资源请求

对于普通的静态资源请求,大型网站通常采用内容分发网络处理。内容分发网络(Content Delivery Network,简称CDN)是建立并覆盖在承载网之上,由分布在不同区域的边缘节点服务器群组成的分布式网络。CDN应用广泛,支持多种行业、多种场景内容加速,例如:图片小文件、大文件下载、视音频点播、直播流媒体、全站加速、安全加速。

只需将其域名的解析权交给CDN的负载均衡设备,CDN负载均衡设备将为用户选择一台合适的缓存服务器,用户通过访问这台缓存服务器来获取自己所需的数据。

其他请求

  1. 后台服务器处理请求,一般要先进行验证,比如安全拦截、跨域验证等等,如果不符合安全验证,直接返回拒绝的http报文
  2. 验证通过后进行请求相应的操作,比如查询、修改、或者计算数据
  3. 执行完毕生成http相应包返回给客户端

浏览器处理响应

解析HTML,构建DOM树

HTML文档会被解析成一棵以document为根的DOM树,解析过程中如果遇到JavaScript,则会暂停解析并传输下载相应的文件造成阻塞。

构建CSS

浏览器根据外部样式,内部样式和内联样式来解析CSS,构建CSSSOM树。

构建渲染树和布局

DOM树和CSSOM树构建完毕后会融合成渲染树,然后浏览器会确认页面各元素的位置。

页面绘制和优化

浏览器根据布局结果进行页面的绘制,并优化页面内容,减小CPU消耗。


访问一个https协议的网站背后的故事
https://chujian521.github.io/blog/2020/11/18/访问一个https协议的网站背后的故事/
作者
Encounter
发布于
2020年11月18日
许可协议