Published on

网络

Authors
  • avatar
    Name
    Reeswell
    Twitter

概述

网络通信是现代计算机系统交互的核心,理解其分层模型、数据传输过程以及安全策略(如同源策略)对前端、后端和全栈开发都至关重要。

5层网络模型详解(OSI简化版)

1. 物理层(Physical Layer)

  • 功能:负责比特流的物理传输,例如通过网线、光纤、无线电波等介质传输0和1
  • 设备:网卡、集线器
  • 关键概念:曼彻斯特编码、调制解调、带宽、速率
  • 功能:将比特组织成帧(Frame),提供相邻节点之间的可靠传输,处理MAC地址寻址和差错控制
  • 协议:Ethernet、PPP
  • 核心功能
    • 帧同步
    • 流量控制
    • 差错检测(CRC校验)
    • MAC寻址
  • 示例:局域网内主机A通过MAC地址找到主机B

3. 网络层(Network Layer)

  • 功能:负责将数据包从源主机发送到目标主机,跨越多个网络
  • 核心协议:IP(IPv4/IPv6)
  • 主要功能
    • 逻辑寻址(IP地址)
    • 路由选择(路由器转发)
    • 分片与重组
  • 协议:IP、ICMP、ARP(用于IP到MAC的映射)
  • 数据单位:数据报(Datagram)或分组(Packet)

4. 传输层(Transport Layer)

  • 功能:提供端到端的通信服务,确保数据可靠、有序传输

主要协议

TCP(Transmission Control Protocol)

  • 面向连接、可靠、基于字节流
  • 适用于HTTP、FTP等
  • 特性
    • 三次握手
    • 四次挥手
    • 滑动窗口
    • 拥塞控制
    • 确认重传机制

UDP(User Datagram Protocol)

  • 无连接、不可靠、速度快
  • 适用于视频流、DNS查询

注意:端口号用于区分同一主机上的不同应用进程(如80为HTTP,443为HTTPS)

5. 应用层(Application Layer)

  • 功能:直接为用户应用提供服务,定义应用间通信的协议
  • 常见协议:HTTP、HTTPS、DNS、SMTP、FTP
  • 数据单位:消息(Message)

数据传输过程

封装与解封装机制

数据在发送时自上而下封装,接收时自下而上解封装

应用层消息 → 传输层加TCP头 → 网络层加IP头 → 数据链路层加帧头/尾 → 物理层比特流

每一层只关心自己的头部信息,形成"封装-解封装"机制。

HTTP请求发送过程详解

以浏览器访问 www.example.com 为例:

步骤1:URL解析

步骤2:DNS解析(应用层)

浏览器检查缓存 → 系统缓存 → 路由器 → ISP DNS服务器 → 根DNS → 顶级域 → 权威DNS

最终获取IP地址,如 93.184.216.34

步骤3:建立TCP连接(传输层)

客户端发起三次握手

  1. SYN(seq=x)
  2. SYN-ACK(seq=y, ack=x+1)
  3. ACK(seq=x+1, ack=y+1)

连接建立成功,进入 ESTABLISHED 状态。

步骤4:TLS握手(若为HTTPS)

客户端发送ClientHello → 服务端回应ServerHello、证书、公钥 → 客户端验证证书、生成会话密钥并加密发送 → 双方协商出对称加密密钥,后续通信加密

步骤5:发送HTTP请求(应用层)

请求报文示例:

GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
...

步骤6:网络层与数据链路层处理

应用层数据 → TCP段(加端口、序列号等)
TCP段 → IP数据报(加源IP、目的IPTTL等)
IP数据报 → 以太网帧(加源MAC、目的MAC帧 → 比特流通过物理介质传输

路由器根据IP地址逐跳转发,交换机根据MAC地址转发。

步骤7:服务器响应

服务器返回HTTP响应(状态码、响应头、响应体),客户端接收后渲染页面。

步骤8:连接关闭(可选)

四次挥手释放TCP连接。


同源策略(Same-Origin Policy)

定义

两个URL的协议(scheme)主机名(host)、**端口(port)**完全相同时,才被认为是同源。

示例

URL1URL2是否同源原因
http://a.com:8080http://a.com:80端口不同
https://a.comhttp://a.com协议不同
a.comb.a.com子域不同

注意:主域名相同但子域不同时,除非显式设置 document.domain,否则非同源

作用

防止恶意脚本读取其他站点的敏感数据(如Cookie、DOM),是Web安全基石之一。

限制范围

  • XMLHttpRequest / Fetch API 请求
  • DOM访问(iframe间)
  • Cookie、LocalStorage访问(受限)

跨域问题(Cross-Origin Resource Sharing, CORS)

成因

浏览器出于安全考虑,阻止前端JavaScript发起跨域请求或读取响应。

常见场景

  • 前端运行在 http://localhost:3000,后端API在 http://api.example.com:8080
  • 静态资源托管在CDN,但接口在另一域名

解决方案

1. CORS(跨域资源共享)——推荐方式

服务端设置响应头

Access-Control-Allow-Origin: https://example.com 或 *
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true(需配合withCredentials)

请求类型

  • 简单请求(Simple Request):满足条件(如GET/POST + 安全头)直接发送
  • 预检请求(Preflight Request):非简单请求先发OPTIONS请求询问是否允许

Node.js Express 示例

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com')
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE')
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  
  if (req.method === 'OPTIONS') {
    res.sendStatus(200)
  } else {
    next()
  }
})

2. 代理服务器(Proxy)

开发环境常用:Webpack DevServer、Vite、Nginx反向代理

原理:前端请求本地服务器,本地服务器转发请求到目标API,绕过浏览器同源限制

Nginx配置示例

location /api/ {
  proxy_pass http://backend-server/api/;
}

3. JSONP(JSON with Padding)——仅支持GET

利用 <script> 标签不受同源策略限制的特性,通过动态创建script标签实现跨域请求。


总结

理解网络模型和跨域机制对于现代Web开发至关重要:

  1. 5层网络模型提供了清晰的分层架构,每层都有明确的职责
  2. HTTP请求过程涉及DNS解析、TCP连接、数据传输等多个步骤
  3. 同源策略是浏览器安全的基础,但也会带来跨域问题
  4. CORS是解决跨域问题的标准方案,需要前后端配合

掌握这些知识有助于更好地理解网络通信原理,解决实际开发中的问题。

浏览器相关

从输入 URL 到页面渲染的流程

输入 URL 之后,浏览器会经历一系列复杂的步骤,包括 URL 解析、DNS 查询、建立 TCP 连接、发送 HTTP 请求、服务器处理并返回响应、浏览器解析渲染页面、以及可能的 HTTPS 安全握手等过程。

主要流程

  1. URL 解析:用户在浏览器地址栏输入 URL(统一资源定位符)
  2. URL 解析:浏览器对 URL 进行解析,提取出协议、主机名、端口、路径等信息
  3. DNS 查询:通过 DNS(域名系统)将域名解析为对应的 IP 地址
  4. 建立 TCP 连接:建立与目标服务器的 TCP 连接(通常使用三次握手)
  5. TLS/SSL 握手:若使用 HTTPS,则还需进行 TLS/SSL 握手以加密通信
  6. 发送 HTTP 请求:浏览器构造 HTTP 请求报文并发送给服务器
  7. 服务器处理:服务器接收请求,处理后返回 HTTP 响应(如 HTML 文档)
  8. 页面渲染:浏览器接收响应数据,开始解析 HTML、构建 DOM 树、CSSOM 树、执行 JavaScript、布局与渲染页面
  9. 资源加载:同时加载页面中的子资源(如图片、CSS、JS 文件),重复类似流程
  10. 完成渲染:最终完成页面展示,并保持连接可选(HTTP 持久连接)或关闭连接

详细技术解析

URL 解析

URL 结构协议://用户名:密码@主机名:端口/路径?查询参数#片段标识符

示例https://www.example.com:8080/path/page.html?name=value#section

浏览器从中提取关键信息用于后续流程,如协议决定是否加密(HTTP vs HTTPS),主机名用于 DNS 查询。

DNS 查询过程(域名解析)

目标:将域名(如 www.example.com)转换为 IP 地址(如 93.184.216.34

查询步骤

  1. 浏览器缓存查询
  2. 操作系统缓存查询
  3. 路由器 DNS 缓存
  4. ISP(互联网服务提供商)的 DNS 服务器
  5. 递归查询:若未命中,发起递归查询,根域名服务器 → 顶级域(.com) → 权威域名服务器

技术细节

  • 使用 UDP 协议,默认端口 53
  • 可能使用 DNS over HTTPS(DoH)或 DNS over TLS(DoT)增强隐私
TCP 三次握手(Transmission Control Protocol)

握手过程

  1. 客户端发送 SYN(同步序列编号)
  2. 服务器回应 SYN-ACK
  3. 客户端发送 ACK 确认
  4. 完成连接建立,进入 ESTABLISHED 状态

核心原理

  • 确保双向通信可靠,基于序列号和确认机制
  • 三次握手防止历史连接请求造成资源浪费
TLS/SSL 握手(针对 HTTPS)

握手过程

  1. 客户端发送 ClientHello(支持的协议版本、加密套件)
  2. 服务器回应 ServerHello(选定协议和加密方式)、证书(含公钥)、可选请求客户端证书
  3. 客户端验证证书(CA 链、有效期、域名匹配)、生成预主密钥,用服务器公钥加密发送
  4. 双方基于预主密钥生成会话密钥
  5. 完成握手,后续通信使用对称加密(如 AES)

目标:实现身份认证、数据加密、完整性保护

HTTP 请求发送

请求构造

  • 构造请求行(如 GET /path HTTP/1.1
  • 添加请求头(Host, User-Agent, Accept, Cookie 等)
  • 若为 POST,包含请求体(如表单数据)
  • 通过已建立的 TCP 连接发送
服务器处理与响应

处理流程

  1. Web 服务器(如 Nginx、Apache)接收请求
  2. 根据路径路由到后端应用(如 Node.js、Java Spring)
  3. 应用处理逻辑(数据库查询、业务计算)
  4. 生成响应(如 HTML 页面)
  5. 返回 HTTP 响应报文:状态码(200 OK)、响应头(Content-Type, Set-Cookie)、响应体
浏览器解析与渲染(Rendering Pipeline)

渲染流程

  1. HTML 解析:接收 HTML 字节流,进行字节 → 字符 → 令牌 → 节点 → DOM 树构建
  2. CSS 解析:遇到 CSS 资源,下载并解析生成 CSSOM(CSS 对象模型)
  3. 构建渲染树:合并 DOM + CSSOM → Render Tree(渲染树)
  4. 布局(Layout / Reflow):计算每个元素的几何位置
  5. 绘制(Paint):将像素信息绘制到图层
  6. 合成(Composite):多个图层合并成最终画面
  7. JavaScript 执行:可能修改 DOM/CSSOM,触发重排或重绘
子资源加载

加载过程

  • 解析 HTML 过程中发现 imglinkscript 标签
  • 对每个资源发起新的 HTTP 请求(可能并行,受限于浏览器并发限制,如 Chrome 约 6 个)
  • JavaScript 默认阻塞 HTML 解析(除非加 asyncdefer
  • CSS 阻塞渲染(render-blocking)
defer和async有哪些区别?

正确答案

<script> 标签的优化方式包括:

  • 使用 deferasync 属性
  • 将脚本放在页面底部
  • 减少脚本数量
  • 延迟加载非关键 JS

其中,deferasync 的区别如下:

  • defer:脚本异步加载,按 HTML 中出现的顺序执行,并且会在文档解析完成后统一执行。
  • async:脚本异步加载,下载完成后立即执行,执行时仍阻塞解析,不保证执行顺序。

它们主要影响页面的首次内容绘制(First Contentful Paint, FCP)和可交互时间(Time to Interactive, TTI)。deferasync 都能提升 FCP,因为不会阻塞 HTML 解析。


1、解答思路

  • 浏览器渲染流程中,默认 <script> 标签会阻塞 HTML 解析直到脚本下载并执行完毕,导致“白屏”或延迟内容渲染。
  • 使用 deferasync 可以避免阻塞,适用于不同场景。
  • 这两种属性通过减少阻塞时间提升 FCP。

2、深度知识讲解

script 标签的优化方式

  • 放置位置:传统做法是将 <script> 放在 </body> 之前,避免阻塞 HTML 解析。
  • 合并与压缩:减少请求数量,使用构建工具压缩代码体积。
  • 异步加载:使用 asyncdefer 属性,让脚本异步加载。
  • 懒加载非关键 JS:如使用动态 import() 按需加载模块。
  • 利用 CDN 加速:缩短资源加载时间。
  • 预加载提示:使用 <link rel="preload"> 提前加载关键脚本。

defer vs async

特性deferasync
加载方式异步加载异步加载
执行时机文档解析完成后统一执行下载完成后立即执行
执行顺序按 HTML 顺序执行不保证顺序
是否阻塞解析
适合依赖 DOM否(可能 DOM 未构建)

对性能指标的影响

  • FCP(首次内容绘制):默认同步脚本会阻塞 HTML 解析,延迟首次渲染。使用 deferasync 可避免阻塞,使内容更早被绘制。
  • TTI(可交互时间):如果脚本包含大量逻辑或事件绑定,会影响 TTI。async 脚本可能更快执行,但也可能更早触发 TTI;defer 通常在最后阶段执行,可能稍晚一些。
  • CLS(累计布局偏移):如果 JS 操作布局或插入样式,可能导致布局偏移,影响 CLS。

3、实现原理(底层机制)

浏览器有两个独立的下载通道:

  1. 一个用于 HTML 解析器
  2. 一个用于预加载扫描器(Preload Scanner)
  • 没有 asyncdefer<script>:HTML 解析器必须暂停,直到脚本下载并执行完毕(解析阻断)。
  • 使用 deferasync 时:
    • 预加载扫描器异步下载脚本
    • 解析器继续解析 HTML
    • defer 脚本加入队列,等 HTML 解析完成后按顺序执行
    • async 脚本下载完成后立即执行,不排队
http2

深度知识讲解:HTTP/2


1. HTTP/2 的背景

  • HTTP/2 是 IETF 标准化的新一代 HTTP 协议(RFC 7540),起源于 Google 的 SPDY 协议。
  • 主要目标:减少页面加载时间、提升性能,尤其在高延迟或高并发场景下表现更优。

2. HTTP/2 与 HTTPS 的关系

  • 协议规范层面:RFC 7540 并未强制要求加密(TLS),理论上可用明文 HTTP/2(h2c, HTTP/2 Clear Text)。
  • 现实部署层面:主流浏览器(如 Chrome、Firefox)出于安全考虑不支持明文 HTTP/2,只允许基于 TLS 的加密版本(h2)。
  • 结论:现代 Web 实际上 HTTP/2 = HTTPS + HTTP/2。

3. 为什么要用 HTTP/2?

  • 安全性:HTTPS 提供端到端加密,防止中间人攻击(MITM)。
  • 多路复用:多个请求可在同一 TCP 连接上并行发送,极大减少延迟。
  • 头部压缩:采用 HPACK 算法,显著减少请求/响应头部体积。
  • 服务器推送:服务端可主动推送资源给客户端,提升首屏速度。

4. TLS 在 HTTP/2 中的作用

  • 推荐使用 TLS 1.2 或更高版本(如 TLS 1.3)建立加密通道。
  • ALPN(Application-Layer Protocol Negotiation) 扩展用于协商 HTTP/2 或 HTTP/1.1。
  • 在 TLS 握手阶段,客户端和服务端通过 ALPN 交换支持的协议列表,最终选择 h2 作为应用层协议。

5. 实现原理简要流程

  • 当客户端发起 HTTPS 请求时:

    1. 客户端发送 ClientHello,包含支持的 TLS 版本、加密套件和 ALPN 列表(如 h2, http/1.1)。
    2. 服务端响应 ServerHello,选择 h2 作为协议。 2. HTTP/2 与 HTTPS 的关系
  • 协议规范层面:RFC 7540 并未强制要求加密(TLS),理论上可用明文 HTTP/2(h2c, HTTP/2 Clear Text)。

  • 现实部署层面:主流浏览器(如 Chrome、Firefox)出于安全考虑不支持明文 HTTP/2,只允许基于 TLS 的加密版本(h2)。

  • 结论:现代 Web 实际上 HTTP/2 = HTTPS + HTTP/2。


3. 为什么要用 HTTP/2?

  • 安全性:HTTPS 提供端到端加密,防止中间人攻击(MITM)。
  • 多路复用:多个请求可在同一 TCP 连接上并行发送,极大减少延迟。
  • 头部压缩:采用 HPACK 算法,显著减少请求/响应头部体积。
  • 服务器推送:服务端可主动推送资源给客户端,提升首屏速度。

4. TLS 在 HTTP/2 中的作用

  • 推荐使用 TLS 1.2 或更高版本(如 TLS 1.3)建立加密通道。
  • ALPN(Application-Layer Protocol Negotiation) 扩展用于协商 HTTP/2 或 HTTP/1.1。
  • 在 TLS 握手阶段,客户端和服务端通过 ALPN 交换支持的协议列表,最终选择 h2 作为应用层协议。

5. 实现原理简要流程

  • 当客户端发起 HTTPS 请求时:

    1. 客户端发送 ClientHello,包含支持的 TLS 版本、加密套件和 ALPN 列表(如 h2, http/1.1)。
    2. 服务端响应 ServerHello,选择 h2 作为协议。
    3. 后续通信使用 HTTP/2 的二进制帧格式进行数据传输。

6. 示例代码(伪代码)

扩展知识点

性能优化技术
  • DNS 预解析:浏览器提前解析页面中可能出现的域名,提升性能
  • 预连接(Preconnect):提前建立 TCP 和 TLS 连接
  • 预加载(Preload):提示浏览器优先加载关键资源
Preload 与 Prefetch 的区别及使用场景
特性Preload(预加载)Prefetch(预取)
用途预加载当前页面即将用到的关键资源(如 JS、CSS、字体等)预加载未来可能用到的资源(如下一页脚本、路由组件等)
加载时机页面解析初期,优先级高,尽早加载浏览器空闲时,优先级低,异步加载
加载保证必须加载,浏览器会确保资源被获取可能加载,浏览器可根据网络状况决定是否加载
典型用法<link rel="preload" href="critical.js" as="script"><link rel="prefetch" href="next-page.js">
适用场景首屏关键 JS、字体、重要样式,减少渲染阻塞SPA 路由级预加载,提升页面切换速度

构建工具集成
如 Webpack 支持自动代码分割 + Prefetch,可为异步路由生成预取指令,实现智能预加载。

小娜提醒:
合理使用 Preload 和 Prefetch 能显著提升用户体验。

  • 过度使用 Preload 可能造成资源竞争,影响主资源加载。
  • 滥用 Prefetch 会浪费带宽。
    建议结合实际用户行为和性能监控进行优化配置。
安全机制
  • 同源策略(Same-Origin Policy):限制跨域资源访问,保障安全
    • 协议、域名、端口相同才视为同源
  • CORS(跨域资源共享):服务器通过响应头(Access-Control-Allow-Origin)允许跨域请求
缓存机制
  • 强缓存Cache-Control, Expires
  • 协商缓存ETag / If-None-Match, Last-Modified / If-Modified-Since

浏览器性能优化

解题思路

浏览器在页面加载和渲染过程中进行了大量优化,主要包括:

  • DNS 预解析
  • TCP 连接复用
  • 资源预加载
  • 关键渲染路径优化
  • DOM 和 CSSOM 构建优化
  • GPU 加速合成
  • JavaScript 执行优化
  • 缓存机制
  • 懒加载与预渲染

这些优化措施贯穿“从用户输入 URL 到页面完全渲染显示”的整个流程。下面按浏览器工作阶段梳理主要优化策略:


1. DNS 预解析(DNS Prefetching)

  • 作用:浏览器提前解析页面中可能出现的域名,减少后续请求的 DNS 查询延迟。
  • 原理:DNS 查询是网络延迟的重要来源之一,预解析可将耗时操作提前执行。
  • 实现:可通过 <link rel="dns-prefetch" href="//example.com"> 或浏览器自动推测。

2. TCP 连接优化

  • 连接池与复用:使用 TCP 连接池和 Keep-Alive,避免每个请求都三次握手。
  • 多路复用:HTTP/2、HTTP/3 支持多路复用,多个请求共用一个连接,减少队头阻塞。
  • 服务器推送:HTTP/2 支持 Server Push,提前发送客户端可能需要的资源。

3. 资源预加载与预取

  • Preload:强制浏览器提前加载关键资源(如字体、JS/CSS),提高加载优先级。
  • Prefetch:浏览器空闲时预加载未来可能用到的资源(如下一页 JS),提升导航速度。
  • 调度:浏览器调度器根据资源类型和优先级安排加载顺序。

4. 关键渲染路径优化(Critical Rendering Path)

  • 首屏优先:优先解析和渲染首屏内容,延迟非关键资源。
  • 优化措施
    • 尽快构建 DOM 和 CSSOM(避免阻塞渲染)
    • 关键 CSS 内联,减少外部阻塞
    • 非关键 JS 异步加载(async/defer)
    • 渲染树仅包含可见元素,避免不必要的计算

5. DOM 与 CSSOM 构建优化

  • 增量解析:边接收 HTML 边构建 DOM,无需等待完整文档。
  • 流式处理:CSS 解析支持流式,但 CSS 是渲染阻塞资源,浏览器会优先下载解析。
  • 高效解析器:如 HTML5 解析算法,快速构建 DOM 树。

6. 布局、绘制与合成优化

  • 分层机制:动画元素提升为合成层(如 transformwill-change),交由 GPU 处理,避免重排重绘。
  • 合成阶段:仅合成图层,不涉及布局和绘制,极大提升性能。
  • 硬件加速:GPU 处理变换、透明度等操作。

7. JavaScript 执行优化

  • JIT 编译:如 V8 引擎将 JS 编译为机器码执行。
  • 隐藏类与内联缓存:提升对象属性访问速度。
  • 垃圾回收优化:分代回收、增量标记等减少卡顿。

8. 缓存机制

  • 强缓存Cache-ControlExpires,资源直接本地读取。
  • 协商缓存ETagLast-Modified,服务器判断是否需要更新。
  • 离线缓存:Service Worker + Cache API,支持 PWA 应用。

9. 懒加载(Lazy Loading)

  • 图片/iframe 懒加载:仅当元素进入视口时才加载,减少初始负载。
  • 原生支持loading="lazy" 属性。
  • JS 实现Intersection Observer 监听元素可见性。

10. 预渲染(Prerendering)

  • 作用:浏览器后台加载并渲染整个页面(如搜索结果中的高概率点击页),用户点击时瞬间显示。
  • 注意:如 <link rel="prerender">,但资源消耗大,需谨慎使用。

11. 内存与资源调度优化

  • 多进程架构:Browser/Renderer/GPU Process 等,隔离页面,提升稳定性和安全性。
  • 沙箱机制:渲染进程权限受限。
  • 资源加载优先级:HTML > CSS > JS > 图片 > prefetch 等。

12. HTTP 缓存与 CDN 协同

  • CDN 优先:浏览器与 CDN 配合,优先从边缘节点获取资源,降低延迟。
  • 高效验证:使用 ETag 等机制。

扩展知识

  • 关键渲染路径(Critical Rendering Path) 是前端性能优化的核心,涉及 DOM、CSSOM、Render Tree、Layout、Paint、Composite 六阶段。浏览器通过多种手段缩短路径。
  • 性能分析工具:Chrome DevTools 的 Performance、Lighthouse 面板可分析优化效果。
  • 新兴 API:如 Priority Hints(<link rel="preload" importance="high">)允许开发者显式指定资源加载优先级。