Tech-Paul

work hard, play hard

1. 用户输入 URL(浏览器发起请求)

  • 用户在浏览器地址栏输入一个 URL,例如 https://www.example.com.
  • 浏览器解析 URL,识别出协议(https://)、域名(www.example.com)和路径(例如 /home)。

2. DNS 解析(域名解析)

  • 浏览器首先需要解析域名 www.example.com 为服务器的 IP 地址。这是通过向 DNS 服务器发送请求完成的。
  • DNS 服务器会返回该域名对应的 IP 地址,如 192.0.2.1。这时,浏览器已经知道如何连接到目标服务器。

3. 建立 TCP 连接(三次握手)

  • 浏览器与目标服务器之间需要建立一个 TCP 连接。这是通过 TCP 协议的“三次握手”完成的:
    1. 浏览器(客户端)向服务器发送一个 SYN 包,表示请求建立连接。
    2. 服务器响应 SYN-ACK 包,表示可以建立连接。
    3. 浏览器再次响应 ACK 包,表示确认连接建立。
  • 在 HTTPS 连接时,还会进行 TLS/SSL 握手,建立加密连接。

4. 浏览器发送 HTTP 请求

  • 浏览器与服务器建立连接后,发送一个 HTTP 请求到服务器。这通常包括以下内容:
    • 请求方法(如 GET、POST、PUT 等)。
    • 请求头(包含如浏览器类型、缓存控制、Cookies 等信息)。
    • 请求体(例如,POST 请求时,可能包含表单数据)。

例如,一个典型的 GET 请求如下:

1
2
3
4
GET /home HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html

5. 服务器处理请求

  • 服务器接收到 HTTP 请求后,首先根据 URL 路径(如 /home)来决定如何处理请求。
  • Web 服务器(如 Nginx, Apache):负责将请求转发给应用服务器或静态文件服务器,并返回响应。
  • 应用服务器(如 Node.js, Django, Ruby on Rails)
    • 如果 URL 需要动态处理(如查询数据库、调用 API 等),应用服务器会根据路由和控制器逻辑处理请求。
    • 如果是静态资源(如图片、CSS、JS 文件等),Web 服务器或应用服务器直接返回静态文件。

6. 应用服务器执行业务逻辑

  • 例如,在 Node.js 应用中,服务器可能会:
    1. 解析查询参数或请求体。
    2. 访问数据库,获取数据(例如从数据库中查询用户信息)。
    3. 执行某些业务逻辑,可能包括身份验证、授权等。
    4. 生成 HTML 或 JSON 响应并返回给浏览器。

假设使用 React 的 SPA(单页面应用)时,应用服务器可能返回一个包含初始 HTML 和嵌入的 JavaScript 文件的响应。

7. 返回 HTTP 响应

  • 服务器在处理完请求后,将 HTTP 响应返回给浏览器,响应通常包括:
    • 响应状态码(如 200 表示成功,404 表示未找到,500 表示服务器错误等)。
    • 响应头(包括服务器信息、缓存策略、内容类型等)。
    • 响应体(如 HTML、JSON、图片等数据)。

例如,一个典型的响应如下:

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

<html>
<head><title>Home Page</title></head>
<body><h1>Welcome to Home Page</h1></body>
</html>

8. 浏览器渲染页面

  • 解析 HTML:浏览器开始解析返回的 HTML 内容,构建 DOM 树(Document Object Model)。

  • 下载并解析 CSS:如果 HTML 中包含 CSS 文件,浏览器会发送请求获取这些 CSS 文件,并根据 CSS 规则构建 CSSOM(CSS Object Model)。

  • 执行 JavaScript:如果 HTML 中有 <script> 标签或内联 JavaScript,浏览器会执行这些 JavaScript 代码。JavaScript 可能会修改 DOM、操作样式或发起异步请求。

    对于 React 等前端框架,JavaScript 会执行应用程序的逻辑,可能会进行路由管理、数据请求等操作。

    • 如果是 SPA(如 React、Vue),浏览器将仅加载一次 HTML 文件,之后通过 AJAX 请求动态加载数据,并更新视图。

9. 页面呈现(显示内容)

  • 浏览器根据解析的 DOM 树和 CSSOM,生成渲染树,并绘制最终的页面内容。
  • 在此过程中,浏览器还会处理页面中的资源加载(如图片、视频等),并通过异步请求加载数据(如通过 AJAX 请求 API 接口获取数据)。

对于现代单页面应用(SPA),渲染过程通常是通过 JavaScript 控制的,可能会通过 React、Vue、Angular 等框架来动态渲染页面内容。

10. 完成加载

  • 页面完全加载并呈现给用户,用户可以与页面互动,如点击按钮、填写表单等。
  • 如果有异步请求(如通过 AJAX 或 Fetch 获取数据),这些请求将在页面加载过程中或加载之后继续进行。

DNS 解析说明

  • 用户在浏览器中输入 URL(如 https://www.example.com)。浏览器首先需要从中提取出域名部分(例如 www.example.com)以进行DNS解析。
  • 浏览器或操作系统会先检查本地 DNS 缓存。这个缓存包含了之前查询过的域名和其对应的 IP 地址。如果域名已经缓存并且没有过期,则可以直接使用缓存中的 IP 地址,跳过后续的 DNS 查询步骤。 - 操作系统 DNS 缓存:操作系统(Windows、Linux 等)会有自己的 DNS 缓存,它存储了最近的 DNS 解析结果。 - 浏览器 DNS 缓存:浏览器也会缓存域名解析结果,用于加速后续请求。
  • 如果缓存中存在有效的记录,则直接返回 IP 地址,跳过接下来的步骤。
  • 查询递归 DNS 解析器
  • 递归 DNS 解析器查询根 DNS 服务器
  • 查询 TLD DNS 服务器
  • 查询权威 DNS 服务器
  • 返回最终的 IP 地址

总结:

从用户输入 URL 到页面呈现的过程,可以分为以下几个主要步骤:

  1. 浏览器发起请求:输入 URL → DNS 解析 → TCP 连接。
  2. 服务器处理请求:Web 服务器转发请求 → 应用服务器处理并返回响应。
  3. 浏览器渲染页面:解析 HTML、CSS 和 JS,构建 DOM 树、CSSOM,并最终呈现页面。

在实际开发中,前后端框架(如 React、Vue、Node.js、Django 等)会对这一过程有所优化和改造,但本质流程是类似的。

Http1.0

浏览器与服务器只保持短暂的链接,浏览器的每次请求都需要和服务器建立一个 TCP 链接(TCP 的每次链接成本很高,都需要 client and service 三次握手和四次挥手),服务器完成请求后立即断开链接,不跟踪每个客户也不记录每次请求

Http1.1

持久链接:引入持久链接,即默认 TCP 不关闭,可以被多个请求复用,大部分浏览器允许同时建立 6 个持久链接;
管道机制:在同一个 TCP 连接里面,client 可以发起多个请求
分块传输编码,即服务端每产生一个数据,就发送一个
新增请求方式:put\delete\options\trace\connect;
缺点:虽然允许复用,但是同一个 tcp 链接里面,所有的通信数据是按次序进行的,服务器只有处理完成一个后才会处理下一个请求,会有排队发生,产生头部阻塞

http2:

采用二进制格式,之前版本采用的是文本格式;
完全多路复用,而非有序并阻塞的,只需要一个链接即可实现并行;解决了头部阻塞的问题
使用报头压缩,降低开销;
1、二进制协议:1.1 版本头信息是文本,(经过 ASCII 编码),数据体可以是文本,也可以是二进制,2.0 版本彻底采用二进制协议,头信息和数据体都是二进制,统称为帧,头信息帧和数据帧,解析起来更高效,错误信息更少;
2、完全多路复用,复用了 TCP 链接,在一个链接里面 client and server 同时可以发送多个请求和响应,不用按照顺序对应,避免头部阻塞;
3、报头压缩
4、服务器推送:HTTP 协议通常承载于 TCP 协议之上,在 http 协议和 tcp 协议之间增加一个安全协议层,SSL 或者 TSL,就成了 https

https 原理

‌HTTPS 是一种应用层协议,是 HTTP 的安全版本,通过传输加密和身份认证保证了传输过程的安全性。它在 HTTP 的基础上引入了一个加密层,使用 SSL/TLS 协议来加密数据包,确保数据在传输过程中的机密性和完整性。

HTTPS 的工作原理主要包括以下几个步骤:

客户端发送 HTTPS 请求到服务器。
服务器返回数字证书(包括公钥)给客户端。
客户端验证证书是否合法,如果合法,则生成一个随机的对称加密密钥。
客户端使用服务器的公钥将该密钥加密,然后发送给服务器。
服务器使用自己的私钥将密钥解密。
服务器和客户端使用该对称密钥进行加密和解密,完成后续的数据传输。在这个过程中,数字证书的作用是验证服务器的身份,确保客户端与服务器之间的通信安全。

TTPS 的优势包括:

保护隐私:所有信息都是加密传播,第三方无法窃听数据。
数据完整性:一旦第三方篡改了数据,接收方会知道数据经过了篡改,保证了数据在传输过程中不被篡改。
身份认证:第三方不可能冒充身份参与通信,因为服务器配备了由证书颁发机构(CA)颁发的安全证书。
HTTPS 被广泛用于万维网上安全敏感的通讯,例如交易支付等方面,确保了网络通信的安全性和可靠性。

理解 Http 缓存

浏览器第一次向一个 web 服务器发起 http 请求后,服务器会返回请求的资源,并且在响应头中添加一些有关缓存的字段如:Cache-Control、Expires、Last-Modified、ETag、Date 等等。之后浏览器再向该服务器请求该资源就可以视情况使用强缓存和协商缓存。

  • 强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互。
  • 协商缓存:浏览器发送请求到服务器,服务器判定是否可使用本地缓存。
  • 联系与区别:两种缓存方式最终使用的都是本地缓存;前者无需与服务器交互,后者需要。

强缓存

如图红线所示的过程代表强缓存。用户发起了一个 http 请求后,浏览器发现先本地已有所请求资源的缓存,便开始检查缓存是否过期。有两个 http 头部字段控制缓存的有效期:Expires 和 Cache-Control,浏览器是根据以下两步来判定缓存是否过期的:

查看缓存是否有 Cache-Control 的 s-maxage 或 max-age 指令,若有,则使用响应报文生成时间 Date + s-maxage/max-age 获得过期时间,再与当前时间进行对比(s-maxage 适用于多用户使用的公共缓存服务器);
如果没有 Cache-Control 的 s-maxage 或 max-age 指令,则比较 Expires 中的过期时间与当前时间。Expires 是一个绝对时间。
注意,在 HTTP/1.1 中,当首部字段 Cache-Control 有指定 s-maxage 或 max-age 指令,比起首部字段 Expires,会优先处理 s-maxage 或 max-age。

另外下面列几个 Cache-Control 的常用指令:

no-cache:含义是不使用本地缓存,需要使用协商缓存,也就是先与服务器确认缓存是否可用。
no-store:禁用缓存。
public:表明其他用户也可使用缓存,适用于公共缓存服务器的情况。
private:表明只有特定用户才能使用缓存,适用于公共缓存服务器的情况。
经过上述两步判断后,若缓存未过期,返回状态码为 200,则直接从本地读取缓存,这就完成了整个强缓存过程;如果缓存过期,则进入协商缓存或服务器返回新资源过程。

协商缓存

当浏览器发现缓存过期后,缓存并不一定不能使用了,因为服务器端的资源可能仍然没有改变,所以需要与服务器协商,让服务器判断本地缓存是否还能使用。此时浏览器会判断缓存中是否有 ETag 或 Last-Modified 字段,如果没有,则发起一个 http 请求,服务器根据请求返回资源;如果有这两个字段,则在请求头中添加 If-None-Match 字段(有 ETag 字段的话添加)、If-Modified-Since 字段(有 Last-Modified 字段的话添加)。注意:如果同时发送 If-None-Match 、If-Modified-Since 字段,服务器只要比较 If-None-Match 和 ETag 的内容是否一致即可;如果内容一致,服务器认为缓存仍然可用,则返回状态码 304,浏览器直接读取本地缓存,这就完成了协商缓存的过程,也就是图中的蓝线;如果内容不一致,则视情况返回其他状态码,并返回所请求资源。下面详细解释下这个过程:

1.ETag 和 If-None-Match
二者的值都是服务器为每份资源分配的唯一标识字符串。

浏览器请求资源,服务器会在响应报文头中加入 ETag 字段。资源更新时,服务器端的 ETag 值也随之更新;
浏览器再次请求资源时,会在请求报文头中添加 If-None-Match 字段,它的值就是上次响应报文中的 ETag 的值;
服务器会比对 ETag 与 If-None-Match 的值是否一致,如果不一致,服务器则接受请求,返回更新后的资源;如果一致,表明资源未更新,则返回状态码为 304 的响应,可继续使用本地缓存,要注意的是,此时响应头会加上 ETag 字段,即使它没有变化。
2.Last-Modified 和 If-Modified-Since
二者的值都是 GMT 格式的时间字符串。

浏览器第一次向服务器请求资源后,服务器会在响应头中加上 Last-Modified 字段,表明该资源最后一次的修改时间;
浏览器再次请求该资源时,会在请求报文头中添加 If-Modified-Since 字段,它的值就是上次服务器响应报文中的 Last-Modified 的值;
服务器会比对 Last-Modified 与 If-Modified-Since 的值是否一致,如果不一致,服务器则接受请求,返回更新后的资源;如果一致,表明资源未更新,则返回状态码为 304 的响应,可继续使用本地缓存,与 ETag 不同的是:此时响应头中不会再添加 Last-Modified 字段。

在 HTTP 通信建立在 TCP 连接基础之上,而 TCP 连接的建立和断开需要经过“三次握手”和“四次挥手”的过程。

一、三次握手(建立连接)

  1. 第一次握手:
    • 客户端向服务器发送一个 SYN(Synchronize Sequence Numbers,同步序列编号)报文段,该报文段中包含客户端的初始序列号(Initial Sequence Number,ISN)。此时客户端进入 SYN_SENT 状态。
    • 这个报文段的作用是告诉服务器,客户端想要建立连接,并告知服务器自己的初始序列号,以便后续的数据传输能够有序进行。
  2. 第二次握手:
    • 服务器收到客户端的 SYN 报文段后,向客户端发送一个 SYN/ACK(Synchronize-Acknowledge,同步确认)报文段。
    • 这个报文段中包含服务器的初始序列号和对客户端 SYN 报文段的确认号(Acknowledgment Number,ACK)。确认号的值为客户端的序列号加一,表示服务器已经收到了客户端的 SYN 报文段,并同意建立连接。此时服务器进入 SYN_RCVD 状态。
  3. 第三次握手:
    • 客户端收到服务器的 SYN/ACK 报文段后,向服务器发送一个 ACK 报文段。
    • 这个报文段中的确认号为服务器的序列号加一,表示客户端已经收到了服务器的 SYN/ACK 报文段,并确认建立连接。此时客户端和服务器都进入 ESTABLISHED 状态,连接建立成功,可以开始进行数据传输。

二、四次挥手(断开连接)

  1. 第一次挥手:
    • 主动关闭方(通常是客户端,但也可能是服务器)发送一个 FIN(Finish,结束)报文段,用来关闭主动方到被动方的数据传送,此时主动方进入 FIN_WAIT_1 状态。
    • 这个报文段的作用是通知被动方,主动方已经没有数据要发送了,希望断开连接。
  2. 第二次挥手:
    • 被动方收到主动方的 FIN 报文段后,向主动方发送一个 ACK 报文段,表示已经收到了主动方的关闭请求。此时被动方进入 CLOSE_WAIT 状态,主动方进入 FIN_WAIT_2 状态。
    • 这个 ACK 报文段只是确认收到了主动方的关闭请求,但被动方可能还有数据要发送给主动方,所以此时连接还没有完全关闭。
  3. 第三次挥手:
    • 被动方发送完所有数据后,也向主动方发送一个 FIN 报文段,表示被动方也没有数据要发送了,希望断开连接。此时被动方进入 LAST_ACK 状态。
    • 这个 FIN 报文段是被动方在确认自己没有数据要发送后发出的,通知主动方可以真正地关闭连接了。
  4. 第四次挥手:
    • 主动方收到被动方的 FIN 报文段后,向被动方发送一个 ACK 报文段,表示已经收到了被动方的关闭请求。此时主动方进入 TIME_WAIT 状态,被动方进入 CLOSED 状态。
    • 经过一段时间的等待(通常为 2 倍的最大报文段生存时间,即 2MSL)后,主动方也进入 CLOSED 状态,连接完全关闭。

“三次握手”和“四次挥手”的过程确保了 TCP 连接的可靠建立和安全断开,保证了数据传输的准确性和完整性。

REST

RESTful API 是一种基于 REST(Representational State Transfer) 架构风格的应用程序编程接口(API)。它是 Web 服务的一种设计模式,主要用于通过 HTTP 协议进行通信,旨在让不同平台和语言之间能够无缝交换数据。

RESTful 是一个遵循 REST 架构原则的 API 设计风格。


REST 的核心原则

RESTful API 主要基于 六大原则,这些原则帮助设计出简洁、可扩展的 Web 服务:

  1. 无状态性(Stateless)

    • 每个请求都是独立的,服务器不会存储客户端的状态。所有的状态信息都应该由客户端在请求中提供。
    • 例如,每次请求必须包括身份验证信息(如 token 或 session 信息)。
  2. 客户端-服务器架构(Client-Server Architecture)

    • 客户端和服务器之间通过 HTTP 协议进行通信,彼此相互独立,互不影响。
    • 客户端专注于用户界面和用户体验,服务器专注于业务逻辑和数据处理。
  3. 统一接口(Uniform Interface)

    • 统一接口简化了系统的架构和组件的交互。使用标准化的 HTTP 方法(如 GETPOSTPUTDELETE)和 URL 路径来定义资源。
    • 例如,GET /users 用来获取所有用户,POST /users 用来创建新用户。
  4. 可缓存性(Cacheable)

    • 客户端可以缓存响应的结果,以减少重复请求的频率,提高性能。
    • 服务器在响应中提供是否可以缓存数据的指示。
  5. 分层系统(Layered System)

    • 系统由多个层次组成,可以通过中间层进行缓存、负载均衡、安全等处理。
    • 客户端不需要知道中间层的存在,客户端和服务器之间的通信是透明的。
  6. 按需代码(Code on Demand)(可选)

    • 服务器可以临时向客户端发送可执行的代码,允许客户端动态扩展功能。
    • 例如,服务器发送 JavaScript 代码来增强客户端的交互。

RESTful API 的基本组成

  1. 资源(Resources)

    • 资源是 RESTful API 的核心,它是通过 URL 标识的对象。例如,/users 代表所有用户,/users/{id} 代表某个特定的用户。
  2. HTTP 方法(HTTP Methods)

    • RESTful API 使用标准的 HTTP 方法来表示对资源的操作。常见的 HTTP 方法有:
      • GET:获取资源(读取数据)。
      • POST:创建资源。
      • PUT:更新资源(替换现有资源)。
      • DELETE:删除资源。

    示例:

    • GET /users 获取所有用户
    • POST /users 创建一个新用户
    • PUT /users/{id} 更新用户信息
    • DELETE /users/{id} 删除用户
  3. 状态码(Status Codes)

    • RESTful API 使用 HTTP 状态码来表示请求的处理结果。
    • 常见的状态码:
      • 200 OK:请求成功并返回数据。
      • 201 Created:成功创建资源。
      • 204 No Content:成功处理请求,但没有返回内容。
      • 400 Bad Request:请求无效,通常是客户端发送了错误的数据。
      • 404 Not Found:请求的资源未找到。
      • 500 Internal Server Error:服务器内部错误。
  4. 请求头(Request Headers)

    • 请求头传递一些关于请求的信息,如认证、请求类型、客户端类型等。
    • 例如,Authorization: Bearer <token> 用于携带认证信息。
  5. 响应体(Response Body)

    • 响应体中通常包含请求的结果,通常是 JSON 格式的数据。
    • 示例:
      1
      2
      3
      4
      5
      {
      "id": 1,
      "name": "Alice",
      "age": 30
      }

RESTful API 的设计原则

  1. 资源命名规范

    • 资源通常使用名词表示,采用复数形式,保持一致性。
    • 示例:
      • GET /users:获取所有用户
      • GET /users/{id}:获取指定用户
      • POST /users:创建新用户
      • PUT /users/{id}:更新用户信息
      • DELETE /users/{id}:删除用户
  2. 层次化路径

    • 资源之间的层次关系应通过 URL 路径体现。例如:
      • GET /users/{id}/posts:获取指定用户的所有帖子。
      • POST /users/{id}/posts:创建指定用户的帖子。
  3. 使用标准 HTTP 方法

    • GET:用于获取资源,不应对服务器的状态或数据产生副作用。
    • POST:用于创建资源或提交数据。
    • PUT:用于更新整个资源。
    • PATCH:用于更新资源的一部分(部分替换)。
    • DELETE:用于删除资源。
  4. 支持分页、过滤和排序

    • 当资源列表很大时,应支持分页、过滤和排序。
    • 例如:
      • GET /users?page=2&limit=10:获取第二页的 10 个用户。
      • GET /users?age=30:获取年龄为 30 的用户。
      • GET /users?sort=name:按名称排序用户。
  5. 支持 HATEOAS(超媒体作为应用状态引擎)

    • 允许响应中包含链接,指向与当前资源相关的其他资源。例如:
      1
      2
      3
      4
      5
      6
      7
      8
      {
      "id": 1,
      "name": "Alice",
      "_links": {
      "self": { "href": "/users/1" },
      "posts": { "href": "/users/1/posts" }
      }
      }

RESTful API 优缺点

优点

  • 简洁易懂:基于 HTTP 协议,使用标准的 HTTP 方法和状态码,容易理解和使用。
  • 独立性:客户端和服务器的分离,客户端与服务器可以独立开发。
  • 可扩展性:可以灵活地扩展和修改 API,不影响现有的系统。
  • 广泛支持:几乎所有的开发平台和语言都支持 RESTful API。

缺点

  • 过于简化:对于复杂的应用场景,RESTful API 可能不够灵活或强大(例如,处理复杂事务或查询可能较为繁琐)。
  • 无法避免过多的请求:对于一些资源依赖较多的应用,RESTful API 可能会导致多次请求(如获取用户和其帖子需要分别请求多个资源)。

Options 方法

OPTIONS 方法是 HTTP 协议中定义的一种请求方法,主要用于查询服务器支持的 HTTP 方法以及 检查跨域请求是否允许。它不会对服务器上的资源产生任何副作用,通常用于客户端在实际请求之前,了解服务器对某个资源支持哪些 HTTP 动作。

  1. 获取支持的 HTTP 方法

    • 当客户端发送 OPTIONS 请求时,服务器会返回一个响应,告知客户端该资源支持哪些 HTTP 方法(如 GET、POST、PUT、DELETE 等)。
  2. 跨域资源共享(CORS)预检请求

    • 在跨域请求(CORS)场景下,浏览器会发送一个 预检请求(Preflight Request),该请求使用 OPTIONS 方法,用来询问目标服务器是否允许跨域请求。

    • 预检请求用于检查浏览器发起的实际请求是否安全,特别是当请求使用了除 GET、POST 或 HEAD 以外的 HTTP 方法,或者使用了自定义头部时。通过预检请求,浏览器能够提前知道服务器是否允许跨域操作。

RESTful API 是基于 HTTP 协议的简洁、灵活的 API 设计风格,能够有效实现不同平台和系统之间的数据交换。它的设计原则强调简洁、清晰、无状态和资源驱动,非常适合大多数 Web 和移动端应用的开发需求。

0%