前端梳理体系从常问问题去完善-网络篇

前言

对于网络,也做了一下问题得整理,估计后面会写flutter文章,因为最近在学flutter,所以干脆,今晚也整理一下网络篇吧,毕竟前端得知识体系,从基本得js,css,html以及ts到react,vue还有构建工具vite,webpack,虽然也有移动端,跨端,小程序,桌面应用eletron,还有node服务。这些体系是很庞大得。这也是根据个人需求,结合自己得项目去完善自己得体系。

通过这两篇先了解一下浏览器得组成吧

浏览器的组成部分及运行原理 - 简书

javascript - 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 - 程序生涯 - SegmentFault 思否

网络

最经典问题:从输入URL到页面加载的过程

javascript - 从输入URL到页面加载的过程?如何由一道题完善自己的前端知识体系! - 程序生涯 - SegmentFault 思否

浏览器的循环机制

浏览器的循环机制(Event Loop,事件循环)是 JavaScript 处理异步操作的核心机制,它决定了代码的执行顺序,尤其是在单线程的 JS 环境中如何协调同步任务、异步任务(如定时器、网络请求、DOM 事件等)的执行。

一、JS 单线程与异步的必要性

  • 单线程:JavaScript 设计为单线程(同一时间只能执行一段代码),这是因为它需要频繁操作 DOM,多线程可能导致 DOM 冲突(比如同时修改和删除同一个元素)。
  • 异步需求 :如果所有操作都是同步的,耗时操作(如网络请求、定时器)会阻塞后续代码执行,导致页面卡顿。因此,浏览器通过 Event Loop 实现了异步操作的非阻塞执行。

二、任务队列(Task Queue)

浏览器将任务分为两类,分别放入不同的队列:

  1. 同步任务(Synchronous Task)
  • 定义:立即执行的任务,在主线程上按顺序执行,前一个任务完成后才能执行后一个。
  • 示例:普通的 console.log()、变量声明、函数调用等。
  1. 异步任务(Asynchronous Task)
  • 定义:不立即执行的任务,会被挂起,待特定条件满足后(如定时器到期、网络请求完成),才会进入任务队列等待执行。
  • 异步任务又分为两种:
    • 宏任务(Macro Task) :包含 Script(整体代码)、setTimeoutsetIntervalsetImmediate(Node 环境)、I/O 操作(如网络请求、文件读写)、DOM 事件(如 clickload)。
    • 微任务(Micro Task) :包含 Promise.then/catch/finallyasync/await(本质是 Promise 语法糖)、queueMicrotaskMutationObserver(监听 DOM 变化的 API)。

三、Event Loop 执行流程

浏览器的 Event Loop 遵循以下步骤,循环往复:

  1. 执行同步任务:先执行主线程中的同步任务,直到同步任务栈为空。
  2. 执行微任务队列 :检查微任务队列,按顺序执行所有微任务 (直到微任务队列为空)。
    • 微任务执行过程中产生的新微任务,会直接加入当前微任务队列末尾,并在本轮一并执行。
  3. 执行宏任务队列 :从宏任务队列中取出第一个任务执行(只执行一个)。
  4. 更新渲染:执行完一个宏任务后,浏览器可能会进行 DOM 渲染(并非每次都渲染,由浏览器优化决定)。
  5. 重复循环:回到步骤 2,继续检查微任务队列,循环往复。

四、关键规则总结

  • 同步任务优先:同步任务全部执行完,才会处理异步任务。
  • 微任务先于宏任务 :每轮 Event Loop 中,微任务队列会被一次性清空,再执行一个宏任务。
  • 宏任务逐个执行:每次只从宏任务队列取一个任务执行,执行后立即处理微任务,再进行下一轮。

五、示例:代码执行顺序分析

通过一个例子理解执行流程:

javascript 复制代码
console.log('1'); // 同步任务

setTimeout(() => {
  console.log('2'); // 宏任务
  Promise.resolve().then(() => console.log('3')); // 微任务
}, 0);

Promise.resolve().then(() => {
  console.log('4'); // 微任务
  setTimeout(() => console.log('5'), 0); // 宏任务
});

console.log('6'); // 同步任务

执行步骤解析

  1. 执行同步任务:console.log('1')console.log('6'),输出 1 6,同步栈为空。
  2. 执行微任务队列:此时微任务队列有 Promise.then(console.log('4'))
    • 执行 console.log('4'),输出 4
    • 该微任务中产生新宏任务 setTimeout(console.log('5')),加入宏任务队列。
    • 微任务队列为空,本轮微任务执行完毕。
  3. 执行宏任务队列:取第一个宏任务 setTimeout(console.log('2'))
    • 执行 console.log('2'),输出 2
    • 该宏任务中产生新微任务 Promise.then(console.log('3')),加入微任务队列。
    • 宏任务执行完毕,检查微任务队列。
  4. 执行新的微任务队列:Promise.then(console.log('3')),输出 3,微任务队列为空。
  5. 执行下一个宏任务:取宏任务队列中的 setTimeout(console.log('5')),执行输出 5

最终输出顺序1 → 6 → 4 → 2 → 3 → 5

六、浏览器与 Node.js 事件循环的差异

虽然核心思想类似,但浏览器和 Node.js 的 Event Loop 存在细节差异:

  • 宏任务执行顺序 :Node.js 中宏任务有更细的分类(如 timerspollcheck 等),执行顺序不同。
  • 微任务优先级 :Node.js 中 process.nextTick(非标准)优先级高于其他微任务,而浏览器中无此 API。

总结

浏览器的 Event Loop 是单线程 JS 处理异步的核心机制,核心流程可概括为:
同步任务 → 清空微任务 → 执行一个宏任务 → (可选渲染)→ 重复

理解这一机制,能帮助我们预测代码执行顺序,避免因异步导致的逻辑错误(如在异步任务中操作未初始化的变量)。

浏览器缓存

浏览器缓存是现代 Web 性能优化的核心机制,通过存储和复用资源(如 HTML、CSS、JS、图片等),显著减少重复请求,提升页面加载速度。以下是其工作原理、分类及最佳实践的详细解析:

一、缓存类型与层次结构

浏览器缓存分为多个层次,按优先级从高到低排列:

  1. Service Worker 缓存
    • 由 JavaScript 控制的可编程缓存,可拦截网络请求并自定义响应。
    • 适用于离线应用、推送通知等高级场景。
  2. 内存缓存(Memory Cache)
    • 临时存储在内存中的资源,读取速度极快,但页面关闭后数据丢失。
    • 通常缓存高频访问的资源(如 JS、图片)。
  3. 磁盘缓存(Disk Cache)
    • 存储在硬盘中的资源,读取速度较慢,但持久性强。
    • 缓存体积较大、不常变化的资源(如 CSS、库文件)。
  4. Push Cache(HTTP/2)
    • 服务器推送的资源缓存,仅在当前会话有效。
  5. 协商缓存(Validation Cache)
    • 资源需与服务器验证是否有更新,再决定是否使用本地副本。

二、缓存控制的核心 HTTP 头

  1. 强缓存(无需请求服务器)

通过 Cache-ControlExpires 控制:

http 复制代码
Cache-Control: max-age=3600      # 资源有效期3600秒
Cache-Control: no-cache         # 强制协商缓存
Cache-Control: no-store         # 禁用所有缓存
Cache-Control: private          # 仅用户浏览器可缓存
Cache-Control: public           # 允许中间代理缓存

Expires 是 HTTP/1.0 的遗留字段,优先级低于 Cache-Control

http 复制代码
Expires: Wed, 21 Oct 2025 07:28:00 GMT  # 资源过期时间点
  1. 协商缓存(需验证)

通过 ETagLast-Modified 实现:

http 复制代码
ETag: "33a64df551425fcc55e4d42a148795d9f25f89"  # 资源内容哈希值
Last-Modified: Tue, 12 Jul 2022 19:15:56 GMT        # 资源最后修改时间

客户端请求时携带验证信息:

http 复制代码
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89"
If-Modified-Since: Tue, 12 Jul 2022 19:15:56 GMT

若资源未修改,服务器返回 304 Not Modified,否则返回新资源(状态码 200)。

三、浏览器缓存决策流程

  1. 检查 Service Worker
    • 若注册且命中缓存,直接返回。
  2. 检查强缓存
    • Cache-ControlExpires 有效,直接使用本地副本。
  3. 执行协商缓存
    • 发送 ETagLast-Modified 验证,根据服务器响应决定是否使用缓存。
  4. 无缓存可用
    • 从服务器获取资源,并更新本地缓存。

四、最佳实践

  1. 静态资源缓存策略
  • 长期缓存(适用于不变的资源,如库文件、图片):

    http 复制代码
    Cache-Control: max-age=31536000, immutable
    • 添加版本号或哈希到文件名(如 app.12345.js),更新时修改文件名触发重新下载。
  • 频繁更新的资源(如业务逻辑 JS):

    http 复制代码
    Cache-Control: max-age=0, must-revalidate
  1. HTML 缓存策略
  • 通常禁用 HTML 强缓存,强制每次验证:

    http 复制代码
    Cache-Control: no-cache
  1. 动态内容缓存
  • 使用

    头指定根据请求头(如

    复制代码
    User-Agent

    )缓存不同版本:

    http 复制代码
    Vary: User-Agent
  1. Service Worker 预缓存
  • 预缓存关键资源,提升离线体验:

    javascript 复制代码
    self.addEventListener('install', (event) => {
      event.waitUntil(
        caches.open('my-cache-v1').then((cache) => {
          return cache.addAll([
            '/',
            '/index.html',
            '/main.css',
            '/app.js'
          ]);
        })
      );
    });
  1. 避免常见陷阱
  • 避免 Cache-Control: public 用于含用户敏感信息的响应。
  • 确保 CDN 配置与源站一致,避免缓存不一致问题。
  • 使用 no-transform 防止中间代理修改资源内容。

五、开发调试技巧

  1. 禁用缓存
    • 开发者工具 → Network → Disable cache(调试时勾选)。
  2. 查看缓存状态
    • 开发者工具 → Network → Size 列:
      • (from memory cache)
      • (from disk cache)
      • 304 Not Modified
  3. 清除缓存
    • 开发者工具 → Application → Clear Storage → Clear site data。

六、常见问题与解决方案

问题 原因 解决方案
新代码未生效 强缓存未过期 使用文件名哈希或降低 max-age
缓存验证频繁 ETag 生成不优化 使用文件内容哈希作为 ETag
CDN 缓存不一致 CDN 配置错误 设置合适的 TTL 和刷新机制
移动端缓存异常 运营商劫持或中间代理问题 使用 HTTPS 和 Cache-Control: no-transform

掌握浏览器缓存机制是构建高性能 Web 应用的基础,合理配置缓存策略可显著提升用户体验并降低服务器负载。

浏览器在什么情况下会造成cookie的参数丢失

浏览器中 Cookie 参数丢失的情况通常与 Cookie 的属性设置、浏览器安全策略、跨域行为或环境限制有关。以下是常见的导致 Cookie 丢失的场景及原因分析:

一、Cookie 属性设置不当

Cookie 的核心属性(如 SecureSameSitePathDomain)若设置不合理,会直接导致浏览器拒绝携带或存储 Cookie。

1. Secure 属性与协议不匹配

  • 规则 :标记为 Secure 的 Cookie 仅能通过 HTTPS 协议 传输,HTTP 协议下浏览器会忽略该 Cookie。
  • 丢失场景
    若服务器在 Cookie 中设置了 Secure=true,但前端页面通过 HTTP 协议加载(或接口请求使用 HTTP),浏览器会拒绝发送该 Cookie,导致参数丢失。

2. SameSite 属性限制跨站请求

用于控制跨站请求时 Cookie 的发送策略,取值包括

  • SameSite=Strict:仅在 同站请求 (域名完全一致)中发送 Cookie,跨站请求(如从 a.comb.com)完全不发送。

  • SameSite=Lax:默认值,跨站的 GET 请求(如链接跳转)可能发送,但跨站的 POST 请求、AJAX 等通常不发送。

  • SameSite=None:允许跨站请求发送,但 必须同时设置 Secure=true(否则浏览器会忽略该 Cookie)。

  • 丢失场景 :

    • 跨站 AJAX 请求(如前端 a.com 调用 b.com 的接口)时,若 b.com 的 Cookie 设置为 SameSite=StrictLax,且请求非 GET 跳转,Cookie 会被浏览器拦截。
    • 若设置 SameSite=None 但未同时设置 Secure=true,浏览器会直接忽略该 Cookie,导致存储失败。

3. Path 属性路径不匹配

  • 规则Path 定义了 Cookie 生效的路径,仅当请求路径 包含或等于 Path 时,浏览器才会发送该 Cookie。
  • 丢失场景
    例如,服务器设置 Cookie 的 Path=/admin,但前端页面或接口请求路径为 /user(不包含 /admin),浏览器会认为路径不匹配,不携带该 Cookie。

4. Domain 属性域名不匹配

  • 规则Domain 定义了 Cookie 生效的域名,仅当请求域名 是该域名的子域名或本身 时,Cookie 才会被发送。若未设置 Domain,默认值为当前请求的域名(不含子域名)。

  • 丢失场景

    • 若服务器设置 Domain=example.com,则子域名 a.example.com 可以携带该 Cookie,但父域名 example.com 本身也可以;但如果设置 Domain=a.example.com,则 example.com 无法携带该 Cookie。
    • Domain 设置为不存在的域名(如拼写错误),浏览器会拒绝存储该 Cookie。

二、跨域请求与 CORS 配置问题

跨域场景下,若前端或服务器的 CORS(跨域资源共享)配置不当,会导致 Cookie 无法在请求中携带。

**1. 跨域请求未开启 withCredentials**

  • 规则 :前端通过 XMLHttpRequestfetch 发起跨域请求时,默认不会携带 Cookie。需显式设置 withCredentials: true(前端),同时服务器需响应 Access-Control-Allow-Credentials: true
  • 丢失场景
    跨域请求时,前端未设置 withCredentials: true,或服务器未返回 Access-Control-Allow-Credentials: true,浏览器会拦截 Cookie,导致请求中不包含 Cookie 参数。

2. CORS 允许的域名与实际不符

  • 规则 :服务器需通过 Access-Control-Allow-Origin 指定允许跨域的前端域名,若设置为 *(通配符),则 无法与 withCredentials: true 同时使用(浏览器会拒绝此类请求)。
  • 丢失场景
    若服务器设置 Access-Control-Allow-Origin: *,但前端开启了 withCredentials: true,浏览器会因安全限制拒绝发送 Cookie,导致丢失。

三、浏览器隐私与安全策略限制

浏览器的隐私模式、安全设置或第三方 Cookie 拦截策略,可能主动阻止 Cookie 的存储或发送。

1. 隐私模式(无痕模式)限制

  • 部分浏览器在隐私模式下会限制 Cookie 的持久化存储,或关闭窗口后自动清除所有 Cookie。若在隐私模式下操作,可能出现 Cookie 临时有效但关闭后丢失,或无法存储的情况。

2. 第三方 Cookie 被拦截

  • 浏览器默认可能拦截

    第三方 Cookie

    (即 Cookie 的

    复制代码
    Domain

    与当前页面域名不同的 Cookie,常见于广告、跟踪脚本等)。例如:

    • 页面 a.com 中嵌入了 b.com 的脚本,该脚本尝试设置 Domain=b.com 的 Cookie,浏览器可能将其视为第三方 Cookie 并拦截,导致存储失败。
    • 部分浏览器(如 Safari)对第三方 Cookie 的限制更严格,默认完全阻止,导致 Cookie 无法生效。

3. 浏览器安全配置或插件拦截

  • 用户可能手动在浏览器设置中开启了 "阻止所有 Cookie" 或 "仅阻止第三方 Cookie",导致 Cookie 无法存储。
  • 浏览器扩展(如广告拦截器、隐私保护插件)可能主动删除或阻止特定 Cookie(尤其是带有跟踪标识的 Cookie)。

四、Cookie 过期或存储限制

1. 过期时间设置导致自动删除

  • 若 Cookie 设置了 Expires(绝对过期时间)或 Max-Age(相对过期时间),到期后浏览器会自动删除该 Cookie,导致参数丢失。
  • 若未设置过期时间,Cookie 为 "会话 Cookie",仅在当前浏览器会话(窗口 / 标签页)存续期间有效,关闭窗口后会被清除。
  1. 超出存储容量限制
  • 浏览器对单个域名的 Cookie 存储容量有限制(通常为 4KB 左右),且总数量限制(通常 50 个左右)。若新 Cookie 超出容量或数量限制,浏览器可能拒绝存储,或覆盖旧 Cookie 导致丢失。

五、服务器或前端代码错误

  1. 服务器设置 Cookie 时响应头格式错误
  • Cookie 需通过 HTTP 响应头

    复制代码
    Set-Cookie

    设置,若格式错误(如缺少必要属性、字符非法),浏览器无法解析,导致 Cookie 存储失败。例如:

    • Set-Cookie 中包含逗号(未转义)、空格等非法字符。
    • 同时设置冲突的属性(如 SameSite=None 未搭配 Secure=true)。

前端代码误操作删除 Cookie

  • 前端通过 document.cookie 手动删除 Cookie(如设置 Max-Age=0 或过期时间为过去),或框架 / 库的自动处理逻辑(如登录状态清除)可能误删 Cookie。

总结

Cookie 参数丢失的核心原因可归纳为:属性配置不匹配(协议、路径、域名、SameSite)、跨域 / CORS 配置错误、浏览器隐私安全限制、过期或存储超限、代码 / 格式错误。排查时需结合具体场景,检查 Cookie 属性、请求协议、跨域配置、浏览器设置及代码逻辑。

如何用cookie做单点登录

cookie常用的属性

http与https的区别?

HTTP(超文本传输协议)和 HTTPS(超文本传输安全协议)是互联网数据传输的两种主要协议,其核心区别在于 安全性数据传输方式。以下是详细对比:

一、核心区别

特性 HTTP HTTPS
安全性 明文传输,数据易被窃听、篡改或冒充 加密传输(SSL/TLS),防窃听、篡改和冒充
端口号 默认 80 默认 443
协议结构 基于 TCP 直接通信 在 TCP 和 HTTP 之间加入 SSL/TLS 层
URL 前缀 http:// https://
证书要求 无需证书 需 SSL/TLS 证书(通常需付费购买)
搜索引擎排名 无优势 Google 等优先收录 HTTPS 网站
浏览器提示 无特殊提示 显示 "安全锁" 图标(有效证书)

二、加密原理(HTTPS)

HTTPS 通过 SSL/TLS 协议 实现加密,采用 对称加密 + 非对称加密 混合模式:

  1. 握手阶段(非对称加密)
    • 客户端向服务器发送支持的加密算法列表。
    • 服务器返回 SSL/TLS 证书(含公钥)和选定的加密算法。
    • 客户端验证证书有效性(通过 CA 机构),生成 会话密钥,并用服务器公钥加密后发送给服务器。
    • 服务器用私钥解密,获取会话密钥。
  2. 数据传输阶段(对称加密)
    • 双方使用 会话密钥(对称加密)加密 / 解密后续通信数据。

优势:结合非对称加密的安全性和对称加密的高效性,确保数据传输安全。

三、证书机制

HTTPS 依赖 SSL/TLS 证书 验证服务器身份,证书由 CA(证书颁发机构) 签发:

  • 证书内容:包含网站域名、公钥、颁发机构、有效期等信息。

  • 验证流程

    1. 浏览器内置全球受信任的 CA 根证书。
    2. 服务器返回证书时,浏览器通过 CA 根证书验证证书签名有效性。
    3. 验证证书中的域名是否与访问域名一致。
  • 分类

    • DV(域名验证):仅验证域名所有权,安全性最低。
    • OV(组织验证):验证域名所有权及组织信息(如公司)。
    • EV(扩展验证) :严格验证组织合法性,浏览器地址栏显示公司名称(如 https://www.paypal.com)。

四、性能影响

HTTPS 因加密过程会引入额外性能开销:

  • 首次连接:SSL/TLS 握手约需 0.2-0.5 秒(具体取决于网络和服务器性能)。

  • 持续优化

    • TLS 会话复用:缓存会话密钥,减少重复握手。
    • HTTP/2:与 HTTPS 强绑定,进一步优化传输效率(如二进制分帧、多路复用)。
    • OCSP Stapling:预获取证书吊销信息,避免在线验证延迟。

五、应用场景

  • 必须使用 HTTPS
    • 涉及用户敏感信息的网站(如登录、支付、个人信息管理)。
    • 移动应用的 API 接口(防中间人攻击)。
    • 需符合合规要求的网站(如 GDPR、PCI-DSS)。
  • 推荐使用 HTTPS
    • 所有网站(Google 已将 HTTPS 列为排名因素之一)。
    • Progressive Web App(PWA)必须使用 HTTPS。
    • 涉及用户交互的页面(如评论、表单提交)。

六、迁移注意事项

从 HTTP 迁移至 HTTPS 需注意:

  1. 证书部署:申请证书并正确配置服务器(如 Nginx、Apache)。
  2. URL 重定向 :配置 HTTP 到 HTTPS 的永久重定向(301 Moved Permanently)。
  3. 混合内容处理:确保页面内所有资源(如图片、脚本)均通过 HTTPS 加载。
  4. Cookie 安全 :设置 Secure 属性,确保 Cookie 仅通过 HTTPS 传输。
  5. SEO 影响:正确配置重定向,避免搜索引擎降权。

七、总结

HTTPS 是 HTTP 的安全升级版,通过加密和身份验证解决了 HTTP 的安全缺陷。随着证书成本降低(如 Let's Encrypt 提供免费证书)和浏览器对 HTTP 的限制(如 Chrome 将 HTTP 标记为 "不安全"),HTTPS 已成为网站的标配。在实际应用中,除非是纯静态且无敏感信息的页面,否则均建议采用 HTTPS。

怎么设置取消预检

在 HTTP 跨域请求中,预检请求(OPTIONS 请求) 是浏览器的一种安全机制,用于验证服务器是否允许实际请求(尤其是 "非简单请求")。预检请求无法被 "完全取消",但可以通过合理配置服务器和优化请求,避免触发预检减少预检请求的频率

一、先明确:什么情况下会触发预检请求?

浏览器对请求进行分类,只有 "非简单请求" 才会触发预检(OPTIONS):

简单请求(不触发预检)需同时满足:

  1. 请求方法 :仅限 GETHEADPOST

  2. 请求头 :仅包含浏览器默认头部(如

    复制代码
    Accept

    复制代码
    Accept-Language

    复制代码
    Content-Language

    ),或

    复制代码
    Content-Type

    为以下之一:

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  3. 无自定义头部(如 X-TokenAuthorization 等,除非服务器明确允许)。

非简单请求(触发预检):

  • 使用 PUTDELETECONNECTOPTIONSTRACEPATCH 等方法;
  • 包含自定义头部(如 X-Requested-WithAuthorization);
  • Content-Typeapplication/jsonapplication/xml 等非简单类型;
  • 携带 withCredentials(跨域携带 Cookie)。

二、如何避免或减少预检请求?

1. 让请求符合 "简单请求" 条件(最直接)

  • 使用 GET/POST/HEAD 方法;

  • 不使用自定义头部(或仅用浏览器默认头部);

  • POST 请求的 Content-Type 设为 application/x-www-form-urlencodedmultipart/form-data(而非 application/json)。

    示例:将 JSON 数据转为表单格式发送,避免 Content-Type: application/json

    javascript 复制代码
    // 避免:Content-Type: application/json(会触发预检)
    fetch('https://api.example.com', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' }, // 非简单类型
      body: JSON.stringify({ name: 'test' })
    });
    
    // 改为:Content-Type: application/x-www-form-urlencoded(简单请求)
    fetch('https://api.example.com', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({ name: 'test' }) // 表单格式
    });

2. 服务器配置:缓存预检结果(减少重复请求)

通过 Access-Control-Max-Age 头设置预检请求的缓存时间(单位:秒),浏览器在缓存有效期内不会重复发送预检。

配置示例(不同服务器):

  • Nginx

    nginx 复制代码
    location / {
      add_header Access-Control-Allow-Origin "https://your-domain.com";
      add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE";
      add_header Access-Control-Allow-Headers "X-Token, Content-Type";
      add_header Access-Control-Max-Age 86400; # 缓存1天(86400秒)
      
      # 处理预检请求(直接返回204)
      if ($request_method = 'OPTIONS') {
        return 204;
      }
    }
  • Node.js(Express)

    javascript 复制代码
    const express = require('express');
    const app = express();
    
    app.use((req, res, next) => {
      res.setHeader('Access-Control-Allow-Origin', 'https://your-domain.com');
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
      res.setHeader('Access-Control-Allow-Headers', 'X-Token, Content-Type');
      res.setHeader('Access-Control-Max-Age', '86400'); // 缓存1天
    
      // 处理预检请求
      if (req.method === 'OPTIONS') {
        return res.sendStatus(204);
      }
      next();
    });
  • Apache(.htaccess):

    apache 复制代码
    Header set Access-Control-Allow-Origin "https://your-domain.com"
    Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
    Header set Access-Control-Allow-Headers "X-Token, Content-Type"
    Header set Access-Control-Max-Age 86400
    
    # 处理预检请求
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteCond %{REQUEST_METHOD} OPTIONS
      RewriteRule ^(.*)$ $1 [R=204,L]
    </IfModule>

3. 避免不必要的跨域场景

  • 若前后端同源(域名、端口、协议一致),则不会触发跨域检查,自然无预检请求;
  • 若必须跨域,可通过 "后端代理"(如 Nginx 反向代理)将跨域请求转为同源请求,绕过浏览器的跨域限制。

三、关键说明

  • 预检请求是浏览器的行为,服务器无法完全禁用(除非不处理跨域请求);
  • 合理配置 Access-Control-Max-Age 可大幅减少预检请求的次数;
  • 对于必须使用非简单请求的场景(如 PUT 方法、application/json 类型),预检请求是必要的安全验证,无法避免。

通过以上方法,可以有效减少预检请求的触发频率,优化跨域请求性能。

TCP三次握手跟四次挥手

csdn如何清除缓存

http2怎么设置优先级

在 HTTP/2 中,请求优先级(Request Prioritization)由客户端设置,用于告知服务器不同请求的相对重要性,帮助服务器优化资源传输顺序。优先级通过流(Stream)的元数据 定义,主要涉及两个核心参数:依赖关系(Stream Dependency)权重(Weight)

一、优先级的核心参数

  1. 依赖关系(Stream Dependency)
    每个请求流(Stream)可以指定依赖另一个流(通过 Stream ID),表示 "当前流需在被依赖流之后处理"。
    • 若不依赖任何流,则为 "根流"(优先级最高的层级)。
    • 依赖关系可形成树状结构(如 CSS 流依赖 HTML 流,图片流依赖 CSS 流)。
  2. 权重(Weight)
    对于依赖同一父流的所有子流,通过权重(1-256 的整数)分配相对优先级:
    • 权重越高,获得的带宽和处理资源越多(按比例分配)。
    • 默认权重为 16

二、如何设置优先级?

优先级由客户端在创建流时通过 HTTP/2 帧的 PRIORITY流的初始设置指定。不同场景下的设置方式如下:

1. 浏览器自动设置(无需手动干预)

现代浏览器(Chrome、Firefox 等)会根据资源类型自动分配优先级,无需开发者手动设置:

  • 最高优先级:HTML 文档、关键 CSS(阻塞渲染的 CSS)。
  • 高优先级:非阻塞 CSS、字体文件。
  • 中优先级:JS 脚本、图片(视口内)。
  • 低优先级:视口外图片、视频等非关键资源。

2. 手动设置(通过代码控制)

若需在自定义 HTTP/2 客户端(如 Node.js、curl 等)中手动设置优先级,需通过 HTTP/2 协议的 API 指定依赖关系和权重。

示例 1:Node.js 中使用 http2 模块设置优先级

javascript 复制代码
const http2 = require('http2');
const client = http2.connect('https://example.com');

// 1. 创建根流(不依赖任何流,权重 256)
const stream1 = client.request({ ':path': '/index.html' }, {
  priority: {
    exclusive: false,  // 是否独占父流的带宽(false 表示与其他子流共享)
    dependency: 0,     // 依赖的流 ID(0 表示无依赖,根流)
    weight: 256        // 权重(1-256)
  }
});

// 2. 创建依赖于 stream1 的子流(权重 128)
const stream2 = client.request({ ':path': '/style.css' }, {
  priority: {
    exclusive: false,
    dependency: stream1.id,  // 依赖 stream1
    weight: 128
  }
});

// 3. 创建依赖于 stream1 的另一个子流(权重 64,优先级低于 stream2)
const stream3 = client.request({ ':path': '/image.jpg' }, {
  priority: {
    exclusive: false,
    dependency: stream1.id,
    weight: 64
  }
});

示例 2:使用 curl 测试优先级(需支持 HTTP/2

bash 复制代码
# 通过 --http2-priorities 选项设置优先级(格式:流ID:依赖ID:权重:是否独占)
curl --http2-priorities "1:0:256:0, 2:1:128:0, 3:1:64:0" https://example.com

三、注意事项

  1. 服务器的自主性:优先级是客户端的 "建议",服务器可根据自身策略调整(如负载过高时可能忽略优先级)。
  2. 避免过度复杂:过多层级的依赖关系可能导致调度效率下降,通常保持简单的树状结构即可。
  3. 与其他特性的配合:优先级需结合多路复用发挥作用,单一连接上的多流才能体现优先级调度的价值。

通过合理设置优先级,可显著提升页面关键资源的加载速度(如优先渲染 HTML 和 CSS),优化用户体验。对于大多数前端开发者,浏览器的自动优先级分配已足够高效,无需手动干预;仅在特殊场景(如自定义客户端)才需手动配置。

http1.1method

HTTP/1.1 定义了一系列请求方法(Method),用于指定客户端对服务器资源的操作类型。这些方法明确了请求的语义,服务器根据方法类型处理请求并返回相应结果。以下是 HTTP/1.1 规范中定义的主要方法及其特点:

  1. GET
  • 作用:请求获取指定资源(如网页、图片、接口数据等)。
  • 特点:
    • 仅用于 "获取" 资源,不应该对服务器资源进行修改(安全方法)。
    • 多次请求同一资源,结果应一致(幂等性)。
    • 请求参数通常附加在 URL 中(有长度限制,因浏览器 / 服务器而异)。
    • 无请求体(body)。
  • 典型场景 :浏览网页、查询数据(如 GET /api/users)。
  1. POST
  • 作用:向服务器提交数据,通常用于创建新资源或触发服务器处理操作(如表单提交)。
  • 特点:
    • 会修改服务器资源(非安全方法)。
    • 多次提交可能产生不同结果(非幂等性,如重复提交订单可能创建多个记录)。
    • 数据放在请求体(body)中,无长度限制(理论上),支持多种格式(如表单、JSON、文件等)。
  • 典型场景 :用户注册、提交表单、上传文件(如 POST /api/users)。
  1. PUT
  • 作用:向指定资源位置上传 / 更新资源,通常用于 "全量更新" 资源。
  • 特:
    • 会修改服务器资源(非安全方法)。
    • 多次请求同一资源,结果一致(幂等性,如多次 PUT 同一内容,最终资源状态相同)。
    • 需要指定资源的完整路径(如 PUT /api/users/123 表示更新 ID 为 123 的用户)。
  • 典型场景:更新用户信息、替换文件内容。
  1. DELETE
  • 作用:请求服务器删除指定资源。
  • 特点:
    • 会删除服务器资源(非安全方法)。
    • 多次请求同一资源,结果一致(幂等性,删除后再删,结果仍是 "不存在")。
  • 典型场景 :删除用户、删除订单(如 DELETE /api/users/123)。
  1. HEAD
  • 作用:与 GET 类似,但仅请求资源的头部信息(响应头),不返回实体主体(body)。
  • 特点:
    • 用于获取资源的元数据(如文件大小、修改时间),而无需下载完整内容。
    • 安全且幂等(同 GET)。
  • 典型场景:检查文件是否存在、获取资源更新时间。
  1. OPTIONS
  • 作用:请求服务器支持的 HTTP 方法(或跨域预检请求)。
  • 特点:
    • 用于 "探测" 服务器能力(如 OPTIONS /api 可返回服务器支持的方法:GET、POST 等)。
    • 在跨域请求中,浏览器会自动发送 OPTIONS 作为 "预检请求",验证服务器是否允许实际请求(如跨域 POST)。
    • 安全且幂等。
  1. TRACE
  • 作用:回显服务器收到的请求,用于测试或诊断(如查看请求经过代理后的变化)。
  • 特点:
    • 服务器会将收到的请求原样返回,帮助排查请求在传输过程中的修改。
    • 因安全风险(可能泄露敏感信息),多数服务器禁用此方法。
    • 安全且幂等。
  1. CONNECT
  • 作用:建立客户端与目标服务器的隧道连接(通常用于 HTTPS 代理)。
  • 特点:
    • 仅用于代理服务器,客户端通过 CONNECT 请求让代理建立与目标服务器的 TCP 连接,之后客户端与目标服务器直接通信(如 HTTPS 握手)。
    • 非安全,非幂等。

补充:方法的 "安全性" 与 "幂等性"

  • 安全性:指请求是否会修改服务器资源(安全方法:GET、HEAD、OPTIONS、TRACE;非安全:POST、PUT、DELETE、CONNECT)。
  • 幂等性:指多次执行同一请求,结果是否一致(幂等方法:GET、HEAD、PUT、DELETE、OPTIONS、TRACE;非幂等:POST)。

这些方法构成了 HTTP/1.1 交互的基础,其中 GET、POST 是最常用的,而 PUT、DELETE 常与 RESTful API 设计结合使用。

http2请求同一域名还会受到浏览器的限制嘛

HTTP/2 几乎消除了 HTTP/1.x 时代 "同一域名并发连接数" 的限制,转而通过 "单个连接的最大并发流数" 进行轻量限制(通常 100 个)。这一限制对绝大多数场景足够宽松,因此实际开发中几乎无需担心同一域名的请求限制,也不再需要依赖 "域名分片" 优化(甚至不推荐,会破坏 HTTP/2 多路复用的优势)。

http2.0新特性

HTTP/2.0 是 HTTP 协议的重大升级(2015 年标准化),旨在解决 HTTP/1.x 的性能瓶颈(如队头阻塞、连接复用效率低等),核心目标是提升传输效率、减少延迟。其主要新特性如下:

  1. 二进制分帧层(Binary Framing)

HTTP/1.x 以文本格式传输数据(换行符分隔),解析复杂且易出错;而 HTTP/2 引入 "二进制分帧" 作为基础传输单位:

  • 将请求 / 响应数据分割为二进制帧(Frame),每个帧包含标识(Stream ID)、类型、长度等元数据。
  • 帧是 HTTP/2 传输的最小单位,可被独立处理、交错发送和重组。
  • 这一设计为后续的 "多路复用""优先级" 等特性奠定了基础。
  1. 多路复用(Multiplexing)

彻底解决 HTTP/1.x 的 "队头阻塞" 问题:

  • HTTP/1.x 中,一个 TCP 连接上只能串行处理请求(或通过多连接并行,但受浏览器连接数限制,通常≤6 个),前一个请求未完成会阻塞后续请求。
  • HTTP/2 允许在单个 TCP 连接上同时传输多个请求 / 响应:不同请求的帧通过 "Stream ID" 标识,接收方会根据 ID 重组为完整的请求 / 响应。
  • 优势:减少 TCP 连接建立 / 关闭的开销(握手、慢启动等),大幅提升并行请求效率。
  1. 头部压缩(Header Compression)

解决 HTTP/1.x 头部冗余问题:

  • HTTP/1.x 每次请求都会携带完整头部(如 User-AgentCookie 等),且未压缩,重复传输大量冗余数据(占请求体积的 40%+)。

  • HTTP/2 使用

    HPACK 算法

    压缩头部:

    • 维护 "静态字典"(预定义常见头部,如 GETHost)和 "动态字典"(记录当前连接中出现过的头部,复用索引)。
    • 对重复头部仅传输索引,非重复头部压缩后传输,减少 50%+ 的头部数据量。
  1. 服务器推送(Server Push)

主动向客户端推送资源,减少请求次数:

  • HTTP/1.x 中,客户端需先请求主资源(如 HTML),解析后才知道需要加载依赖资源(如 CSS、JS),再发起二次请求,增加延迟。
  • HTTP/2 允许服务器在客户端请求一个资源时,主动推送相关依赖资源(无需客户端显式请求)。
  • 示例:客户端请求 index.html 时,服务器可主动推送 style.cssapp.js,节省一轮请求 - 响应时间。
  1. 请求优先级(Request Prioritization)

优化资源加载顺序:

  • 客户端可对不同请求设置优先级(0-255,数值越小优先级越高),服务器根据优先级调度帧的发送顺序。
  • 例如:优先加载关键 CSS/HTML,再加载图片等非关键资源,提升页面渲染速度。
  1. 流量控制(Flow Control)

避免接收方被过量数据淹没:

  • 基于 "流"(Stream)和 "连接" 两级控制:接收方通过 WINDOW_UPDATE 帧告知发送方可传输的最大数据量(窗口大小)。
  • 确保接收方(如浏览器)有足够的缓冲区处理数据,防止内存溢出或拥塞。

总结

HTTP/2.0 通过二进制分帧 重构了传输层,结合多路复用 解决了连接效率问题,通过头部压缩 减少带宽消耗,再配合服务器推送优先级优化加载体验,最终实现了比 HTTP/1.x 更高的性能(实测页面加载速度提升 50%+ 很常见)。

不过,HTTP/2 仍基于 TCP 协议,存在 TCP 层的队头阻塞问题(单个数据包丢失会阻塞整个连接),这一问题在 HTTP/3(基于 QUIC 协议)中得到了进一步解决。

http2.0多路复用如何实现得

HTTP/2 的多路复用(Multiplexing)是其解决 HTTP/1.x 性能瓶颈的核心特性,主要通过二进制分帧层(Binary Framing Layer) 实现,允许在单一 TCP 连接上并行传输多个请求 / 响应,彻底解决了 HTTP/1.x 中 "队头阻塞"(Head-of-Line Blocking)问题。

核心实现原理:

  1. 二进制分帧层(基础)

HTTP/2 不再使用 HTTP/1.x 的文本格式传输数据,而是将所有传输内容分割为二进制帧(Frame)

  • 帧是 HTTP/2 传输的最小单位,每个帧大小固定(默认最大 16KB),包含头部(Frame Header)和 payload(数据)。
  • 帧头部包含 流 ID(Stream ID)(用于标识所属的 "流")、帧类型(如 HEADERS 帧、DATA 帧等)、长度等元信息。
  1. 流(Stream):多请求的并行载体
  • 流的定义:流是一组有序帧的集合,对应一个完整的请求 / 响应(如客户端向服务器发送的一个请求,或服务器返回的一个响应)。

  • 唯一标识:每个流有唯一的整数 ID(客户端发起的流为奇数,服务器发起的为偶数),帧通过流 ID 关联到特定流。

  • 并行性 :多个流(即多个请求 / 响应)的帧可以在同一个 TCP 连接上交错传输(无需按顺序),接收方通过帧的流 ID 重新组装成完整的请求 / 响应。

    例如:在一个 TCP 连接上,客户端可以同时发送请求 A 的 HEADERS 帧、请求 B 的 DATA 帧、请求 A 的 DATA 帧,服务器通过流 ID 区分并分别处理。

  1. 解决队头阻塞问题
  • HTTP/1.x 中,一个 TCP 连接同一时间只能处理一个请求,后续请求必须排队等待前一个完成(队头阻塞),多请求需建立多个 TCP 连接(受浏览器连接数限制,通常 6-8 个)。
  • HTTP/2 中,单一 TCP 连接上的多个流并行传输,某一流的帧传输延迟(如丢包)不会阻塞其他流,仅影响该流自身的组装,大幅提升效率。
  1. 流的其他特性(辅助优化)
  • 优先级:可以为流设置优先级(通过帧头部的 Priority 字段),服务器会根据优先级分配资源(如优先处理高优先级的流),优化用户体验(如优先加载页面关键资源)。
  • 流控制:支持流量控制机制,避免接收方被发送方的大量数据淹没(类似 TCP 滑动窗口)。
  • 双向性:流是双向的,客户端和服务器可在同一流上交替发送帧(如 WebSocket 式的双向通信)。

总结

HTTP/2 多路复用的核心是通过二进制分帧 将请求 / 响应拆分为独立的帧,再通过流 ID 标识归属,使多个请求 / 响应的帧能在单一 TCP 连接上交错传输,实现并行处理。这一机制减少了 TCP 连接建立的开销(如握手、慢启动),解决了队头阻塞,显著提升了网络传输效率。

tcp 的拥塞控制是怎么做的

TCP 的拥塞控制是为了避免网络因数据量过大而发生拥塞(如路由器缓存溢出、链路过载),同时最大化利用网络带宽的关键机制。其核心思路是通过动态调整发送方的发送速率(即 "拥塞窗口"),根据网络实时状态(是否发生丢包、延迟增加等)自适应调整,实现 "探测 - 适应 - 稳定" 的闭环。

TCP 拥塞控制主要通过四个核心算法协同工作:慢启动(Slow Start)拥塞避免(Congestion Avoidance)快速重传(Fast Retransmit)快速恢复(Fast Recovery)。下面详细说明其工作机制:

核心概念:拥塞窗口(cwnd)与慢启动阈值(ssthresh)

在了解具体算法前,需要先明确两个关键变量:

  • 拥塞窗口(cwnd,Congestion Window):发送方维护的一个动态值,代表当前允许发送的未确认数据的最大字节数(或报文段数量),直接决定发送速率。
  • 慢启动阈值(ssthresh,Slow Start Threshold) :一个临界值,用于划分 "慢启动" 和 "拥塞避免" 两个阶段。当 cwnd < ssthresh 时,使用慢启动;当 cwnd ≥ ssthresh 时,使用拥塞避免。

1. 慢启动(Slow Start):逐步探测网络承载能力

当 TCP 连接刚建立(或从拥塞中恢复后),发送方对网络状况一无所知,此时需要通过 "慢启动" 逐步探测网络能承受的最大数据量。

  • 规则
    初始时,cwnd 设为较小值(通常为 1~2 个 MSS,MSS 是最大报文段长度),ssthresh 设为一个较大值(如 65535 字节)。
    每收到一个对端的确认报文(ACK),cwnd翻倍 (指数增长)。
    例如:初始 cwnd=1 → 收到 ACK 后 cwnd=2 → 再收到 ACK 后 cwnd=4 → 以此类推。
  • 目的:避免一开始就发送大量数据导致网络拥塞,通过指数增长快速接近网络的承载上限。
  • 终止条件 :当 cwnd 增长到等于 ssthresh 时,慢启动结束,进入 "拥塞避免" 阶段。

2. 拥塞避免(Congestion Avoidance):平稳增长,避免拥塞

cwnd 达到 ssthresh 后,说明已接近网络的承载上限,此时需要放缓增长速度,避免触发拥塞。

  • 规则
    每经过一个往返时间(RTT,数据发送到收到 ACK 的时间),cwnd增加 1 个 MSS (线性增长)。
    例如:cwnd=10 → 经过一个 RTT 后 cwnd=11 → 再经过一个 RTT 后 cwnd=12
  • 目的:通过线性增长逐步试探网络的最大容量,在保证网络稳定的前提下最大化吞吐量。

3. 拥塞发生时的处理:根据 "丢包信号" 调整策略

当网络发生拥塞时,发送方会通过两种信号感知:超时重传(Timeout)收到 3 个重复 ACK(Duplicate ACK)。两种信号对应不同的处理逻辑。

情况 1:超时重传(严重拥塞信号)

如果发送方超过重传超时时间(RTO)仍未收到 ACK,说明报文可能因网络严重拥塞而丢失(缓存溢出被丢弃)。

  • 处理规则:
    1. ssthresh 设为当前 cwnd 的一半(ssthresh = cwnd / 2),减少后续发送量。
    2. cwnd 重置为初始值(1 个 MSS),重新进入 "慢启动" 阶段,彻底降低发送速率。

情况 2:收到 3 个重复 ACK(轻微拥塞信号)

如果发送方收到 3 个相同的 ACK(重复确认),说明有报文段丢失,但网络仍在正常传输(否则不会收到 ACK),属于轻微拥塞。

  • 快速重传(Fast Retransmit)
    不等待超时,立即重传丢失的报文段(无需等到 RTO),减少重传延迟。
  • 快速恢复(Fast Recovery)
    1. ssthresh 设为当前 cwnd 的一半(ssthresh = cwnd / 2)。
    2. cwnd 设为 ssthresh + 3(加 3 是因为 3 个重复 ACK 说明已有 3 个报文段被接收,网络仍有一定容量)。
    3. 之后每收到一个重复 ACK,cwnd 增加 1;当收到新的 ACK(确认重传的报文段)后,cwnd 恢复为 ssthresh,进入 "拥塞避免" 阶段。
  • 目的:在轻微拥塞时,避免重新进入慢启动(减少吞吐量波动),快速恢复发送速率。

整体流程示例

假设初始 cwnd=1ssthresh=16

  1. 慢启动阶段cwnd 从 1→2→4→8→16(指数增长),当 cwnd=16 时达到 ssthresh,进入拥塞避免。
  2. 拥塞避免阶段cwnd 线性增长(16→17→18→...)。
  3. 若发生超时重传ssthresh=18/2=9cwnd=1,重新慢启动(1→2→4→8→9),再进入拥塞避免(9→10→...)。
  4. 若收到 3 个重复 ACKssthresh=18/2=9cwnd=9+3=12,快速恢复后进入拥塞避免(12→13→...)。

总结

TCP 拥塞控制通过 "慢启动" 快速探测网络容量,"拥塞避免" 平稳增长发送速率,再通过 "快速重传" 和 "快速恢复" 处理不同程度的拥塞,动态平衡 "吞吐量" 和 "网络稳定性"。这一机制是 TCP 能在复杂网络环境中可靠传输数据的核心保障。

udp 和 tcp 区别

TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protocol,用户数据报协议)是 TCP/IP 协议栈中最核心的两个传输层协议,它们在设计目标、工作方式和适用场景上有显著区别,核心差异体现在可靠性、连接性、传输效率等方面。

1. 连接性:是否需要建立连接

  • TCP面向连接
    通信前必须通过 "三次握手" 建立连接,通信结束后通过 "四次挥手" 释放连接,就像打电话前先拨号确认对方接听,挂电话前说 "再见"。
    例:TCP 连接建立后,发送方和接收方会维护一个 "连接状态"(如序号、窗口大小等),确保双方状态同步。
  • UDP无连接
    通信前无需建立连接,发送方直接封装数据并发送,接收方收到后直接处理,就像发快递 ------ 直接填地址寄出,不需要提前通知收件人。
    例:UDP 发送数据时,不关心接收方是否在线、是否准备好接收,发送后也不保留连接状态。

2. 可靠性:是否保证数据完整送达

  • TCP可靠传输

    通过一系列机制确保数据不丢失、不重复、按序到达

    • 确认应答(ACK):接收方收到数据后必须返回确认,发送方未收到确认则重传。
    • 超时重传:发送方若超过一定时间未收到 ACK,自动重传数据。
    • 序号与确认号:给每个数据包编号,接收方按序号重组,发现缺失则要求重传。
    • 校验和:检测数据传输中是否损坏,损坏则丢弃并要求重传。

    例:用 TCP 传输文件,即使中途有数据包丢失,最终也能通过重传保证文件完整。

  • UDP不可靠传输

    仅提供最基本的校验和(检测数据损坏),若损坏则直接丢弃,不保证送达、不保证顺序、不重传

    例:UDP 发送的数据包可能丢失、重复或乱序到达,接收方收到后也无需确认。

3. 传输方式:字节流 vs 数据报

  • TCP字节流传输
    数据被视为连续的字节流(无边界),发送方和接收方通过 "滑动窗口" 控制数据流量,接收方会将收到的字节按顺序拼接成完整数据。
    例:发送 "ABCDE",TCP 可能分两次发送 "A" 和 "BCDE",接收方会自动拼接为 "ABCDE"。
  • UDP数据报传输
    数据以 "数据报" 为单位独立传输(有明确边界),每个数据报包含完整的源 / 目的端口和数据,接收方会按数据报原样处理,不会合并或拆分。
    例:发送 "ABCDE",若用 UDP 分两次发送,则接收方会收到两个独立的数据报(如 "AB" 和 "CDE"),不会自动拼接。

4. 效率与开销:速度与资源占用

  • TCP效率低,开销大
    为实现可靠性,TCP 需要维护连接状态、处理确认 / 重传、拥塞控制等,头部开销较大(20~60 字节),传输速度较慢。
  • UDP效率高,开销小
    无连接状态维护,无确认 / 重传机制,头部仅 8 字节(固定),传输速度快,资源占用低。

5. 拥塞控制与流量控制

  • TCP有拥塞控制和流量控制
    • 流量控制:通过 "滑动窗口" 限制发送方速率,避免接收方缓冲区溢出(接收方告诉发送方可接收的最大数据量)。
    • 拥塞控制:通过慢启动、拥塞避免等算法(见前文)动态调整发送速率,避免网络拥塞。
  • UDP无拥塞控制和流量控制
    发送方会以恒定速率发送数据,不考虑网络状态和接收方能力,可能导致网络拥塞或接收方缓冲区溢出。

6. 适用场景

  • TCP :适合对可靠性要求高、可接受延迟 的场景,如:
    • 文件传输(FTP、HTTP/HTTPS):需保证文件完整。
    • 邮件发送(SMTP):不能丢失邮件内容。
    • 登录交互(SSH、Telnet):指令需准确执行。
  • UDP :适合对实时性要求高、可容忍少量数据丢失 的场景,如:
    • 实时音视频(视频通话、直播):少量丢包不影响整体体验,延迟更重要。
    • 游戏数据(多人在线游戏):位置、操作等实时数据,延迟过大会影响体验。
    • 广播 / 组播(如 DNS 查询):简单请求 - 响应,无需复杂控制。

总结对比表

特性 TCP(传输控制协议) UDP(用户数据报协议)
连接性 面向连接(三次握手建立连接) 无连接(直接发送)
可靠性 可靠(不丢失、不重复、按序到达) 不可靠(可能丢失、乱序)
传输单位 字节流(无边界) 数据报(有边界)
头部大小 20~60 字节(可变) 8 字节(固定)
拥塞 / 流量控制
速度 较慢 较快
适用场景 文件传输、HTTP、邮件等 音视频、游戏、DNS 等

简单说,TCP 像 "挂号信"(确保送达),UDP 像 "平信"(快速但不保证到)------ 选择哪种协议,取决于应用更在意 "可靠性" 还是 "实时性"。

说一下 udp 的使用场景

UDP(用户数据报协议)的设计核心是高效率、低延迟 ,但不保证可靠性,因此它的使用场景主要集中在对实时性要求高、可容忍少量数据丢失的场景中。以下是 UDP 的典型应用场景及背后的逻辑:

1. 实时音视频传输(如视频通话、直播、 VoIP)

  • 核心需求:实时性优先,延迟必须低(通常要求 < 200ms),少量数据丢失不影响整体体验。
  • 为什么用 UDP
    音视频数据是连续的 "流",如果某个数据包丢失,TCP 会触发重传,导致后续数据积压,产生 "卡顿" 或 "延迟累积"(比如直播中画面突然卡住,几秒后又快进播放)。而 UDP 不重传丢失的包,接收方可以通过算法(如丢包补偿、插值)填补缺失,保证画面 / 声音流畅,用户几乎感知不到少量丢包。
  • 例子:Zoom、腾讯会议的实时视频、抖音直播、网络电话(Skype 早期核心协议)。

2. 在线游戏(尤其是实时竞技类游戏)

  • 核心需求:低延迟传输玩家操作、位置、状态等数据,确保 "操作即时反馈"。
  • 为什么用 UDP
    游戏中玩家的位置、按键操作等数据具有 "时效性",比如 1 秒前的位置数据即使重传到达,也已失去意义(玩家早已移动)。TCP 的重传机制会导致数据延迟,引发 "操作卡顿"(比如按了技能,几秒后才生效)。而 UDP 快速传输,即使少量数据包丢失,游戏客户端可以通过 "预测算法"(如根据前几帧位置预测当前位置)临时填补,保证游戏流畅。
  • 例子:《英雄联盟》《王者荣耀》《CS:GO》等竞技游戏的核心数据传输。

3. DNS(域名解析)

  • 核心需求:短请求 - 响应模式,追求快速解析,单次交互数据量小。
  • 为什么用 UDP
    DNS 查询通常是 "客户端发送一个短请求(如查询www.baidu.com的 IP),服务器返回一个短响应",整个过程数据量极小(通常 <512 字节),UDP 的低开销(8 字节头部)和无连接特性可以快速完成交互。即使偶尔丢包,客户端也会简单重试,效率远高于 TCP 的 "三次握手建立连接→传输→四次挥手释放连接" 的完整流程。

4. 广播与组播通信

  • 核心需求:一对多或多对多的数据分发(如局域网设备发现、实时消息推送)。
  • 为什么用 UDP
    TCP 是 "点对点" 的连接协议,不支持广播(向局域网所有设备发送)或组播(向特定组设备发送)。而 UDP 天然支持广播和组播,适合局域网内的设备发现(如打印机自动连接、智能家居设备配对)、企业内部的实时通知推送等场景。

5. IoT(物联网)设备通信

  • 核心需求:低资源消耗(算力、带宽),简单高效的数据上报或控制。
  • 为什么用 UDP
    物联网设备(如传感器、智能手表、摄像头)通常硬件资源有限(CPU 弱、内存小),UDP 的无连接特性和低头部开销(8 字节)可以减少设备的计算负担和网络流量。例如,温度传感器每秒上报一次数据,即使偶尔丢失一次,后续数据仍能反映趋势,无需 TCP 的复杂可靠性机制。

6. 实时监控与远程控制

  • 核心需求:低延迟传输监控画面或控制指令。
  • 为什么用 UDP
    安防摄像头的实时视频流、无人机 / 机器人的远程控制指令,对延迟非常敏感(比如无人机操作指令延迟 1 秒可能导致碰撞)。UDP 的快速传输能保证指令即时生效,少量视频帧丢失不会影响监控画面的整体观察。

总结:UDP 的适用场景共性

所有 UDP 的典型场景都符合一个核心逻辑:"实时性> 绝对可靠性",即 "少量数据丢失可以接受,但延迟必须低"。相比之下,TCP 更适合 "可靠性 > 实时性" 的场景(如文件传输、邮件)。

简单说,UDP 就像 "对讲机"------ 快速传递信息,偶尔没听清可以再问;而 TCP 像 "挂号信"------ 确保送到,但过程较慢。选择哪种协议,本质是权衡 "实时性" 和 "可靠性" 的优先级。

整个 DNS 域名查询过程是怎么样子的

DNS(域名系统)的核心作用是将人类易记的域名(如www.baidu.com)转换为计算机可识别的 IP 地址(如180.101.50.242)。整个查询过程可以分为 "本地查询" 和 "网络查询" 两个阶段,涉及多种类型的 DNS 服务器协同工作,以下是详细步骤:

整体流程概览

当用户在浏览器输入www.baidu.com并回车后,DNS 查询流程大致为:
本地缓存 → 本地DNS服务器 → 根域名服务器 → 顶级域名服务器 → 权威域名服务器

(每一步若找到结果,会立即返回并缓存,无需进入下一步)

详细步骤拆解

1. 检查本地缓存(最快的查询)

首先,浏览器和操作系统会优先检查 "本地缓存" 中是否有该域名对应的 IP 地址:

  • 浏览器缓存:浏览器会保存近期查询过的域名 - IP 映射(缓存时间由 DNS 记录的 TTL 决定,通常几分钟到几小时)。
  • 操作系统缓存 :如果浏览器缓存中没有,会查询操作系统的本地 DNS 缓存(如 Windows 的hosts文件或系统级缓存)。

结果:若缓存中有记录,直接返回 IP 地址,查询结束(整个过程在本地完成,耗时毫秒级)。

2. 向 "本地 DNS 服务器" 发起查询(递归查询)

如果本地缓存无记录,操作系统会向 "本地 DNS 服务器"(通常由网络服务商 ISP 提供,如电信、联通,或用户手动设置的公共 DNS 如114.114.114.1148.8.8.8)发送查询请求。

  • 这种查询是递归查询:本地 DNS 服务器会 "全权负责",要么返回结果,要么向其他服务器查询,直到拿到结果。

3. 本地 DNS 服务器查询(迭代查询)

本地 DNS 服务器若自身缓存中没有该域名的 IP(称为 "非权威查询"),会通过迭代查询的方式,逐级向上级 DNS 服务器查询:

Step 3.1:查询 "根域名服务器"

根域名服务器是 DNS 体系的 "顶层",全球共 13 组(编号 A~M),负责指引到 "顶级域名服务器"。

  • 本地 DNS 服务器向根服务器发送查询:"请问www.baidu.com的 IP 是多少?"
  • 根服务器不直接存储具体域名的 IP,但知道 ".com" 这类顶级域名对应的服务器地址,因此返回:"我不知道,但你可以问.com顶级域名服务器,它的地址是 XXX"。

Step 3.2:查询 "顶级域名服务器(TLD)"

顶级域名服务器负责管理 "顶级域名"(如.com.cn.org)下的二级域名。

  • 本地 DNS 服务器向.com顶级域名服务器发送查询:"请问www.baidu.com的 IP 是多少?"
  • 顶级域名服务器知道 "baidu.com" 这个二级域名对应的 "权威域名服务器" 地址,因此返回:"我不知道,但你可以问baidu.com的权威服务器,它的地址是 YYY"。

Step 3.3:查询 "权威域名服务器"

权威域名服务器是域名的 "所有者服务器",由企业或组织自己维护(或委托给服务商),直接存储该域名对应的 IP 地址(及其他 DNS 记录,如 MX、CNAME 等)。

  • 本地 DNS 服务器向baidu.com的权威服务器发送查询:"请问www.baidu.com的 IP 是多少?"
  • 权威服务器查询自身记录,返回对应的 IP 地址(如180.101.50.242)。

4. 结果返回与缓存

  • 本地 DNS 服务器收到权威服务器返回的 IP 后,会将该记录缓存(按 TTL 时间保存),以便下次查询时直接使用。
  • 本地 DNS 服务器将 IP 地址返回给用户的操作系统,操作系统再返回给浏览器。

5. 浏览器发起连接

浏览器拿到 IP 地址后,通过 TCP 协议与该 IP 对应的服务器建立连接(如三次握手),最终获取网页内容并展示。

关键概念补充

  • 递归查询 vs 迭代查询:
    • 递归:"你帮我查到结果为止"(用户设备 → 本地 DNS 服务器)。
    • 迭代:"我不知道,但你可以去问 XXX"(本地 DNS 服务器 → 根 / TLD / 权威服务器)。
  • TTL(生存时间):DNS 记录的缓存时长(单位秒),过期后会重新查询,保证 IP 地址变更时能及时更新。
  • CNAME 记录 :如果www.baidu.com是一个别名(如指向baidu.com),权威服务器会先返回 CNAME,本地 DNS 需要再查一次别名对应的 IP。

示例:查询www.baidu.com的简化流程

  1. 浏览器 / 系统缓存:无记录。
  2. 本地 DNS(如114.114.114.114):无缓存,开始迭代查询。
  3. 根服务器 → 指引到.com TLD 服务器。
  4. .com TLD 服务器 → 指引到baidu.com的权威服务器。
  5. baidu.com权威服务器 → 返回www.baidu.com的 IP(如180.101.50.242)。
  6. 本地 DNS 缓存该 IP,返回给浏览器,浏览器连接服务器。

整个过程看似复杂,但由于缓存机制和服务器优化(如根服务器、TLD 服务器的分布式部署),实际耗时通常在几十到几百毫秒,用户几乎无感知。

get与post的区别

在 HTTP 协议里,GET 和 POST 是两种常用的请求方法,二者存在诸多不同,下面为你详细介绍:

应用场景

  • GET:主要用于获取服务器上的资源。比如,当你在浏览器中输入网址查看网页,或者通过搜索引擎进行搜索时,使用的就是 GET 请求。
  • POST:常用于向服务器提交数据,像表单提交、文件上传等操作都会用到 POST 请求。

参数传递方式

  • GET :请求参数会附加在 URL 的查询字符串里,例如 https://example.com/api?name=John&age=30
  • POST:请求参数包含在请求体中,不会直接显示在 URL 里。

安全性

  • GET:由于参数直接暴露在 URL 中,所以不太适合传输敏感信息,如密码、银行卡号等。而且,GET 请求容易被浏览器缓存,也可能被记录在日志中,存在一定的安全风险。
  • POST:参数位于请求体中,相对更安全一些,适合传输敏感数据。不过,即便使用 POST 请求,在传输敏感信息时,也建议结合 HTTPS 协议来保障数据的安全性。

数据长度限制

  • GET:URL 的长度是有限制的,不同浏览器和服务器的限制可能有所不同,一般在 2048 字节左右,所以 GET 请求能携带的参数长度也受到相应限制。
  • POST:理论上对请求体的大小没有限制,但实际应用中,服务器通常会设置一个最大限制,以防止恶意攻击或者占用过多资源。

幂等性

  • GET:是幂等的请求方法,也就是说,多次执行相同的 GET 请求,得到的结果都是一样的,不会对服务器上的资源造成改变。
  • POST:不具备幂等性,多次提交 POST 请求可能会导致服务器上的资源发生多次改变,比如多次创建相同的记录。

缓存机制

  • GET:请求会被浏览器缓存,如果你再次访问相同的 URL,浏览器可能会直接使用缓存的结果,而不会重新向服务器发送请求。
  • POST:默认情况下,POST 请求不会被缓存。

编码方式

  • GET :URL 只能使用 ASCII 字符集,所以非 ASCII 字符需要进行编码,通常采用 URL 编码(比如 %E4%B8%AD%E6%96%87 表示中文)。
  • POST :请求体的编码方式由 Content-Type 头指定,常见的编码方式有 application/x-www-form-urlencodedmultipart/form-dataapplication/json 等。

适用场景总结

场景 GET POST
获取数据 ✅ 合适 ❌ 不太合适
提交数据(如表单) ❌ 不安全,参数会暴露在 URL 中 ✅ 合适
传输敏感信息 ❌ 不安全 ✅ 相对安全
幂等操作 ✅ 多次请求结果相同 ❌ 多次请求可能产生不同结果
大数据传输 ❌ 受 URL 长度限制 ✅ 适合大数据传输

示例代码

下面是使用 Python 的 requests 库分别发送 GET 和 POST 请求的示例:

python 复制代码
import requests

# GET 请求示例
response_get = requests.get('https://example.com/api', params={'name': 'John', 'age': 30})
print(response_get.url)  # 输出: https://example.com/api?name=John&age=30

# POST 请求示例
response_post = requests.post('https://example.com/api', data={'name': 'John', 'age': 30})
print(response_post.text)  # 输出服务器响应内容

总结

在实际开发过程中,要根据具体的业务需求来选择合适的请求方法。如果是获取数据,优先考虑使用 GET 请求;如果是提交数据或者执行会对服务器资源产生修改的操作,建议使用 POST 请求。同时,要特别注意敏感数据的传输安全问题,尽量使用 HTTPS 协议来保障通信安全。

http1 的队头堵塞

HTTP/1 中的队头阻塞(Head-of-Line Blocking,简称 HoLB) 是指在一个 TCP 连接上,前面的请求未完成时,后面的所有请求都必须排队等待,从而导致后续请求被阻塞的现象。这是 HTTP/1.x 协议设计的核心性能瓶颈之一。

为什么会产生队头阻塞?

HTTP/1.x 对请求的处理遵循「串行化 」原则,即使使用了 keep-alive 持久连接(复用 TCP 连接),同一连接上的请求也必须按顺序执行:

  • 客户端必须等待前一个请求的响应完全接收后,才能发送下一个请求。
  • 若前一个请求因网络延迟、服务器处理缓慢、丢包重传等原因被阻塞,后续所有请求都会被「卡」在队列中,无论它们本身是否准备好发送 / 处理。

举例说明

假设一个网页需要加载 5 个资源(如 CSS、JS、图片),且浏览器通过一个 TCP 连接请求这些资源:

  1. 客户端发送请求 1 → 等待服务器响应。
  2. 若请求 1 因服务器处理慢(比如需要复杂计算),耗时 3 秒才返回响应。
  3. 则请求 2、3、4、5 必须在队列中等待 3 秒,直到请求 1 完成后才能依次发送。
  4. 即使请求 2 的资源很小、服务器能瞬间处理,也必须等待请求 1 完成,这就是典型的「队头阻塞」。

队头阻塞的影响

  1. 页面加载延迟
    网页通常依赖多个资源(几十甚至上百个),队头阻塞会导致资源加载顺序混乱、整体耗时增加,尤其影响首屏渲染速度。
  2. 连接数膨胀
    为缓解队头阻塞,浏览器会对同一域名开启多个并行 TCP 连接 (通常限制 6-8 个),试图让不同连接上的请求并行处理。但这会带来新问题:
    • 多连接会重复经历 TCP 握手、慢启动等过程,增加额外开销。
    • 过多连接可能触发 TCP 拥塞控制(如丢包时所有连接同时降速),反而降低整体效率。
  3. 资源利用率低
    即使服务器空闲,也无法处理被阻塞在队列后的请求,导致网络和服务器资源浪费。

为什么 HTTP/1 无法解决?

HTTP/1.x 基于「文本协议」传输,请求 / 响应的格式是明文且无结构化拆分,服务器必须完整接收一个请求后才能解析并处理下一个。这种设计导致无法在同一连接上交错处理多个请求,只能串行执行,从而根本上无法避免队头阻塞。

总结

HTTP/1 的队头阻塞本质是「同一 TCP 连接上的请求串行化处理」导致的连锁阻塞问题,是协议设计的固有缺陷。这一问题在 HTTP/2 中通过「二进制分帧 + 多路复用」机制得到解决(多个请求的帧可在同一连接上交错传输,互不阻塞),成为 HTTP/2 性能提升的核心原因之一。

对 http1的keep-alive 的了解。keep-alive 具体alive多久?

在 HTTP/1 中,keep-alive 是用于实现持久连接(Persistent Connections) 的机制,其核心作用是复用已建立的 TCP 连接,避免每次 HTTP 请求都重复进行 TCP 三次握手和四次挥手,从而减少网络开销、提升传输效率。

一、keep-alive 的基本原理

HTTP 协议最初是 "短连接" 模式:每个 HTTP 请求 / 响应完成后,底层的 TCP 连接会被立即关闭。这导致在加载一个包含多个资源(如图片、CSS、JS)的网页时,需要频繁创建和关闭 TCP 连接,而 TCP 握手、慢启动等过程会显著增加延迟。

keep-alive 机制通过以下方式优化:

  • 客户端和服务器通过 HTTP 头协商,在一个 TCP 连接上连续发送多个 HTTP 请求(无需重复建立连接)。
  • 当一段时间内没有新请求时,连接才会被关闭。

二、keep-alive 的协商方式

  • HTTP/1.0 :默认不启用持久连接,需显式通过请求头 Connection: keep-alive 告知服务器 "希望复用连接";服务器若同意,会在响应头中同样返回 Connection: keep-alive
  • HTTP/1.1 :默认启用持久连接(无需显式设置 Connection: keep-alive),除非通过 Connection: close 明确关闭。

三、keep-alive 具体 "存活多久"?

keep-alive 的连接持续时间没有固定标准 ,由服务器配置客户端行为共同决定,核心依赖两个参数:

  1. 服务器端的超时时间(timeout

服务器会通过响应头 Keep-Alive 中的 timeout 参数指定 "连接空闲超时时间",例如:
Keep-Alive: timeout=5, max=100

  • timeout=5:表示服务器在处理完一个请求后,会保持连接等待 5 秒。若 5 秒内客户端发送新请求,则复用该连接;超过 5 秒无新请求,服务器会主动关闭连接。
  • max=100:表示该连接最多可处理 100 个请求,即使未超时,处理完 100 个请求后也会关闭连接(避免连接长期占用资源)。

不同服务器的默认配置不同(可自定义):

  • Nginx 默认 timeout=60s(可通过 keepalive_timeout 配置)。
  • Apache 默认 timeout=5s(可通过 KeepAliveTimeout 配置)。

2. 客户端的超时策略

客户端(如浏览器、curl、应用程序)也会设置自己的 "连接空闲超时时间",可能比服务器的 timeout 更短:

  • 例如,浏览器可能设置为 30 秒,若 30 秒内没有新请求,会主动关闭连接,无需等待服务器超时。
  • 客户端也可能限制单个连接处理的最大请求数(如浏览器对同一域名的并发连接数限制,间接影响连接复用次数)。

3. 其他关闭条件

  • 若服务器或客户端检测到网络异常(如丢包、断开),会立即关闭连接。
  • 客户端或服务器主动发送 Connection: close 头,告知对方 "本次请求后关闭连接"。

四、注意:与 TCP keep-alive 的区别

HTTP 的 keep-alive 和 TCP 协议的 keep-alive 是完全不同的机制:

  • HTTP keep-alive:属于应用层机制,目的是复用 TCP 连接,减少连接建立开销。
  • TCP keep-alive:属于传输层机制,用于检测已建立的 TCP 连接是否 "存活"(如长时间无数据传输时,发送探测包确认对方是否在线),与 HTTP 复用无关。

总结

keep-alive 的 "存活时间" 由服务器的 timeout 配置(如 Nginx 默认 60 秒)和客户端的超时策略共同决定,核心是 "空闲多久后关闭连接"。其本质是通过复用 TCP 连接优化性能,但 HTTP/1 的 keep-alive 仍存在 "队头阻塞" 问题(同一连接上的请求需排队),这一缺陷在 HTTP/2 中被多路复用机制解决。

webScoket 和 http2 服务端推送的差异

WebSocket 和 HTTP/2 服务端推送(Server Push)虽然都能实现服务器向客户端主动发送数据,但它们的设计目标、通信模式、适用场景有本质区别,核心差异体现在 "双向实时通信" 与 "资源预加载优化" 的定位上。

1. 设计目标:解决的问题不同

  • WebSocket
    核心目标是打破 HTTP 协议 "请求 - 响应" 的单向通信限制,建立客户端与服务器之间的全双工(双向)实时通信通道
    解决的问题:HTTP 中服务器无法主动向客户端发送数据(除非客户端轮询,效率低),WebSocket 让双方可随时互相发送数据,适合实时交互场景。
  • HTTP/2 服务端推送
    核心目标是优化 HTTP 协议的 "资源请求效率",通过服务器主动推送客户端可能需要的关联资源 ,减少客户端的请求次数和延迟。
    解决的问题:传统 HTTP 中,客户端请求一个主资源(如 HTML)后,需解析后再依次请求依赖资源(如 CSS、JS、图片),多次往返耗时;HTTP/2 推送让服务器在响应主请求时,主动 "预推送" 这些依赖资源,加速页面加载。

2. 通信模式:双向实时 vs 单向预推

  • WebSocket

    • 连接方式 :需单独建立持久连接(握手阶段基于 HTTP,但之后使用独立的 WebSocket 协议帧),连接一旦建立,客户端和服务器可随时双向发送数据(全双工),无需等待对方请求。
    • 数据类型:通常传输动态实时数据(如聊天消息、实时位置、游戏状态),数据格式灵活(文本、二进制)。
    • 触发方式:服务器可主动推送数据,客户端也可主动发送数据,双方行为互不依赖。

    例:聊天应用中,服务器可随时向客户端推送新消息,客户端也可随时发送消息给服务器,双方实时交互。

  • HTTP/2 服务端推送

    • 连接方式 :基于 HTTP/2 现有的持久连接(复用同一 TCP 连接,利用多路复用特性),仅支持服务器向客户端单向推送,且推送行为必须依附于客户端的某个初始请求(不能无中生有地推送)。
    • 数据类型:主要推送静态资源(如 CSS、JS、图片、字体),这些资源是客户端请求的主资源(如 HTML)的依赖项。
    • 触发方式 :服务器只能在处理客户端的某个请求(如请求 index.html)时,预判客户端接下来可能需要的资源(如 style.css),主动推送;若客户端没有任何请求,服务器无法主动推送。

    例:客户端请求 index.html 时,服务器在返回 HTML 的同时,主动推送 index.cssmain.js,避免客户端解析 HTML 后再发起这两个请求的延迟。

3. 协议基础与生命周期

  • WebSocket
    • 是独立的应用层协议(RFC 6455),握手时使用 HTTP 协议(通过 Upgrade 头部升级连接),但握手成功后脱离 HTTP,使用 WebSocket 帧格式传输数据。
    • 连接生命周期:一旦建立,会长期保持(除非主动关闭或超时),适合长时间的实时通信。
  • HTTP/2 服务端推送
    • 是 HTTP/2 协议(RFC 7540)的内置特性,完全基于 HTTP/2 的帧结构(如 PUSH_PROMISE 帧标记推送意图),属于 HTTP 协议的增强。
    • 推送生命周期:依附于客户端的请求上下文,推送的资源是对该请求的 "补充",连接虽持久,但推送行为与具体请求强关联。

4. 适用场景:实时交互 vs 性能优化

  • WebSocket 适用场景
    实时双向交互 的场景,核心诉求是 "低延迟、高频次、双向通信":
    • 即时通讯(如微信网页版、在线聊天)
    • 实时数据展示(如股票行情、监控数据)
    • 多人协作工具(如在线文档实时编辑)
    • 在线游戏(如实时同步玩家操作)
  • HTTP/2 服务端推送适用场景
    优化资源加载效率 的场景,核心诉求是 "减少请求次数、加速页面 / 应用加载":
    • 网页加载(推送 HTML 依赖的 CSS、JS、图片)
    • 移动端应用资源预加载(推送首页依赖的静态资源)
    • API 响应时推送关联数据(如请求用户信息时,推送其常用设置数据)

5. 关键差异总结表

维度 WebSocket HTTP/2 服务端推送
核心目标 建立双向实时通信通道 预推送关联资源,优化加载效率
通信方向 全双工(客户端↔服务器双向) 单向(仅服务器→客户端)
触发条件 连接建立后,双方可随时触发 必须依附于客户端的某个初始请求
传输内容 动态实时数据(消息、状态等) 静态依赖资源(CSS、JS、图片等)
协议基础 独立协议(基于 HTTP 握手) HTTP/2 内置特性
典型场景 聊天、实时游戏、协作工具 网页加速、资源预加载

一句话总结

WebSocket 是 "实时对话的电话",支持双方随时互聊;HTTP/2 服务端推送是 "快递员主动送件",在你下单买了一件商品后,提前把你可能需要的配件一起送来,减少你再次下单的麻烦。两者定位不同,无法互相替代,但可结合使用(如一个应用用 WebSocket 做实时交互,同时用 HTTP/2 推送静态资源优化加载)。

websocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它允许客户端和服务器之间进行实时数据传输,是现代 Web 实时应用(如聊天、实时通知、游戏、股票行情等)的核心技术。以下是关于 WebSocket 的详细解析:

一、核心概念与特点

  1. 与 HTTP 的对比
特性 HTTP WebSocket
通信模式 半双工(请求 - 响应) 全双工(双向实时通信)
连接特性 短连接(每次请求新建) 长连接(一次握手,长期保持)
实时性 低(需轮询或长轮询) 高(消息即时推送)
协议开销 高(每次请求带完整头) 低(仅握手阶段开销大)
端口 80/443 80(ws)/443(wss)
  1. 协议握手过程

  2. 客户端发起升级请求

    客户端通过 HTTP 请求(带特殊头)向服务器请求升级协议:

    http 复制代码
    GET /chat HTTP/1.1
    Host: example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Sec-WebSocket-Version: 13
  3. 服务器响应升级

    服务器验证请求合法后,返回 101 状态码,表示协议升级成功:

    http 复制代码
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  4. TCP 连接保持

    握手成功后,HTTP 连接升级为 WebSocket 连接,使用相同的 TCP 通道进行通信,后续数据传输不再需要 HTTP 头。

二、API 与使用示例

  1. 浏览器端 API
javascript 复制代码
// 创建 WebSocket 实例
const ws = new WebSocket('ws://example.com/socket');

// 连接建立成功
ws.onopen = () => {
  console.log('WebSocket 连接已建立');
  ws.send('Hello, server!'); // 发送消息
};

// 接收消息
ws.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

// 连接关闭
ws.onclose = (event) => {
  console.log('连接已关闭', event.code, event.reason);
};

// 错误处理
ws.onerror = (error) => {
  console.error('WebSocket 错误:', error);
};

// 关闭连接
ws.close();
  1. 服务端实现(Node.js 示例)

使用 ws 库(需先安装:npm install ws):

javascript 复制代码
const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

// 监听新连接
wss.on('connection', (ws) => {
  console.log('客户端已连接');

  // 接收客户端消息
  ws.on('message', (message) => {
    console.log('收到消息:', message);
    ws.send(`服务器收到: ${message}`); // 回复消息
  });

  // 连接关闭
  ws.on('close', () => {
    console.log('客户端已断开');
  });
});

三、高级特性

  1. 心跳机制

为保持长连接活跃(避免被中间代理断开),需定期发送心跳包:

javascript 复制代码
// 客户端代码
let heartbeatInterval;

function startHeartbeat() {
  heartbeatInterval = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send('ping'); // 发送心跳
    }
  }, 30000); // 每30秒发送一次
}

// 连接建立后启动心跳
ws.onopen = () => {
  startHeartbeat();
};

// 关闭连接时清除心跳
ws.onclose = () => {
  clearInterval(heartbeatInterval);
};
  1. 二进制数据支持

WebSocket 支持发送二进制数据(如图片、文件):

javascript 复制代码
// 发送二进制数据(如 File 对象)
const file = document.querySelector('input[type="file"]').files[0];
ws.send(file);

// 接收二进制数据
ws.onmessage = (event) => {
  if (event.data instanceof Blob) {
    // 处理二进制数据
    const reader = new FileReader();
    reader.onload = () => {
      // 使用 reader.result
    };
    reader.readAsArrayBuffer(event.data);
  }
};
  1. 跨域与安全
  • 同源策略 :WebSocket 默认不受同源策略限制,但服务器可通过验证 Origin 头控制允许的域名。
  • 加密连接 :使用 wss:// 协议(基于 TLS)替代 ws://,确保数据传输安全。

四、应用场景

  1. 实时通信:聊天应用(如 Slack、微信网页版)、在线客服。
  2. 实时数据推送:股票行情、体育比分、实时监控系统。
  3. 协同编辑:多人在线文档编辑(如 Google Docs)、实时协作绘图。
  4. 游戏:多人在线游戏(如实时对战、聊天室)。
  5. 实时通知:社交平台消息推送、邮件提醒。

五、与其他实时技术的对比

技术 实现方式 延迟 开销 适用场景
WebSocket 全双工长连接 极低 高频实时数据(如股票)
轮询(Polling) 定时发送 HTTP 请求 数据更新频率低的场景
长轮询(Long Polling) 服务器保持请求直到有数据 中等 中等 实时性要求一般的场景
Server-Sent Events(SSE) 服务器单向推送 仅需服务器到客户端的场景

六、常见问题与解决方案

  1. 连接断开处理
    • 实现重连机制(如指数退避算法:setTimeout(reconnect, Math.min(delay * 2, maxDelay)))。
    • 使用心跳包检测连接状态。
  2. 消息顺序保证
    • 为消息添加序列号,客户端按序处理。
    • 使用可靠传输协议(如 WebSocket 本身是可靠的,但需处理重连后的数据同步)。
  3. 安全性
    • 使用 wss:// 协议。
    • 服务端验证客户端身份(如 JWT 令牌)。
    • 限制消息大小,防止 DOS 攻击。
  4. 跨域问题
    • 服务端配置允许的域名(验证 Origin 头)。
    • 使用代理服务器(如 Nginx)转发 WebSocket 请求。

七、服务端框架推荐

  • Node.jsws(轻量)、Socket.IO(自动重连、心跳、跨浏览器兼容)、uWebSockets.js(高性能)。
  • Java:Spring WebSocket、Jetty WebSocket。
  • Pythonwebsockets、Django Channels。
  • Gogorilla/websocket

WebSocket 凭借其低延迟、高实时性和双向通信能力,成为构建现代 Web 实时应用的首选技术。合理处理连接管理、消息协议和安全问题,可打造出高性能、稳定的实时系统

http2.0对服务端渲染有什么好处

HTTP/2.0 作为新一代 HTTP 协议,其核心特性(如多路复用、服务器推送、头部压缩等)对服务端渲染(SSR,Server-Side Rendering)的性能和用户体验有显著优化,主要好处体现在以下几个方面:

  1. 多路复用解决 "队头阻塞",加速资源并行加载

HTTP/1.x 中,单个 TCP 连接同一时间只能处理一个请求 / 响应,多资源加载时需建立多个连接(或排队等待),容易出现 "队头阻塞"(Head-of-Line Blocking)问题。而 SSR 页面通常需要加载大量关联资源(如 HTML 主文档、CSS、JS、图片等),资源加载效率直接影响首屏渲染速度。

HTTP/2.0 的多路复用通过二进制分帧技术,允许在单个 TCP 连接上同时传输多个请求 / 响应(每个请求被拆分为独立帧,通过流 ID 标识),无需等待前一个请求完成即可处理下一个。这对 SSR 的优势在于:

  • 服务器生成的 HTML 主文档与它引用的 CSS、JS 等资源可通过同一个连接并行传输,减少连接建立和 TLS 握手的开销;
  • 避免因某个资源加载缓慢(如大图片)阻塞其他关键资源(如 CSS)的传输,从而加快首屏渲染的 "关键路径"。
  1. 服务器推送(Server Push)减少请求延迟

SSR 的核心是服务器提前生成 HTML 并发送给客户端,但客户端解析 HTML 后仍需额外请求其引用的资源(如 <link rel="stylesheet"><script>),这会产生 "请求 - 响应" 的往返延迟。

HTTP/2.0 的服务器推送允许服务器在客户端显式请求前,主动推送关联资源。例如:

  • 服务器生成 HTML 时,发现其中引用了 main.cssapp.js,可在发送 HTML 的同时,主动将这些资源推送到客户端;
  • 客户端接收 HTML 时,所需的 CSS/JS 可能已缓存完成,无需再发起请求,直接用于渲染,显著减少首屏加载的总时间。

这对 SSR 尤为重要 ------SSR 本就是为了减少客户端渲染的延迟,而服务器推送进一步消除了 "资源依赖请求" 的额外开销。

  1. 头部压缩(HPACK)降低传输开销

HTTP 请求 / 响应的头部(Headers)在 HTTP/1.x 中以文本形式传输,且包含大量重复信息(如 User-AgentCookieAccept 等),尤其在 SSR 场景中,多个资源请求的头部冗余会浪费带宽并增加延迟。

HTTP/2.0 采用HPACK 算法对头部进行压缩:

  • 通过静态字典(预定义常见头部字段)和动态字典(记录当前连接中重复的头部),大幅减少头部的传输体积;
  • 对 SSR 中多资源并行请求的场景,头部压缩可降低总数据传输量,间接提升资源加载速度,尤其在弱网环境下效果更明显。
  1. 连接复用减少 TCP 握手成本

HTTP/1.x 中,浏览器对同一域名的并发连接数有限制(通常 6-8 个),多资源加载时可能需要建立多个 TCP 连接,每个连接都需经历 "三次握手" 和 TLS 握手(若用 HTTPS),成本较高。

HTTP/2.0 基于单个 TCP 连接实现多路复用,所有请求 / 响应都在这一个连接上完成,避免了多连接的建立开销:

  • 对 SSR 页面中包含大量图片、样式、脚本等资源的场景,减少了连接建立的时间成本;
  • 降低服务器的连接管理压力,提升服务端处理 SSR 并发请求的效率。

总结

HTTP/2.0 通过多路复用消除队头阻塞、服务器推送减少请求延迟、头部压缩降低传输成本、连接复用减少握手开销等特性,直接优化了 SSR 场景中 "资源加载效率" 和 "首屏渲染速度" 这两个核心痛点。这些优化使得 SSR 页面能更快地将内容呈现给用户,进一步发挥 SSR 在首屏体验和 SEO 上的优势。

SSL/TLS实现得过程

对称加密和非对称加密的区别

对称加密和非对称加密是密码学中两种核心加密方式,它们在密钥管理、安全性、效率等方面存在显著区别,以下是具体对比:

1. 密钥使用方式

  • 对称加密
    加密和解密使用同一个密钥 (称为 "对称密钥")。发送方用密钥加密数据,接收方必须使用相同的密钥才能解密。
    例如:A 用密钥 K 加密信息发送给 B,B 必须用 K 才能解密。
  • 非对称加密
    加密和解密使用一对不同但关联的密钥 (公钥和私钥):
    • 公钥(Public Key):可公开传播,用于加密数据或验证签名。
    • 私钥(Private Key):必须保密,用于解密用公钥加密的数据,或生成签名。
      例如:A 用 B 的公钥加密信息,只有 B 的私钥能解密;或 A 用自己的私钥签名,任何人可用 A 的公钥验证签名。

2. 密钥管理与分发

  • 对称加密
    密钥必须严格保密,且需要安全地传递给通信对方(即 "密钥分发问题")。如果密钥在传输中泄露,加密内容会被破解。
    (例如:A 和 B 必须先通过安全渠道共享密钥 K,否则无法安全通信。)
  • 非对称加密
    公钥可公开传播,无需保密,只需确保私钥不泄露即可。解决了对称加密的密钥分发难题:接收方只需公开公钥,发送方用公钥加密,无需提前共享密钥。

3. 安全性

  • 对称加密
    安全性依赖于密钥的保密性和长度。密钥一旦泄露,所有加密数据都会被破解;但只要密钥安全,加密本身很难被攻破(如 AES 算法)。
  • 非对称加密
    安全性基于复杂的数学难题(如大整数分解、离散对数),破解难度极高。即使公钥公开,没有私钥也无法解密或伪造签名。但私钥一旦泄露,整个加密体系会失效。

4. 效率与适用场景

  • 对称加密
    算法简单(如 AES、DES),加密解密速度极快,适合处理大量数据 (如文件加密、实时通信加密)。
    缺点:密钥分发困难,不适合跨网络的陌生节点通信(如互联网用户之间)。
  • 非对称加密
    算法复杂(如 RSA、ECC),加密解密速度较慢,不适合大量数据加密。
    优势:适合密钥交换 (如用非对称加密传递对称密钥)、数字签名 (验证身份和数据完整性)、身份认证等场景(如 HTTPS 协议中用 RSA 交换对称密钥)。

5. 典型算法

  • 对称加密:AES(Advanced Encryption Standard)、DES、3DES、RC4 等。
  • 非对称加密:RSA、ECC(Elliptic Curve Cryptography)、DSA(Digital Signature Algorithm)等。

总结

维度 对称加密 非对称加密
密钥 单密钥(加密 / 解密共用) 公钥(公开)+ 私钥(保密)
密钥分发 需安全渠道,难度高 公钥可公开,无分发难题
效率 速度快,适合大量数据 速度慢,适合小数据 / 密钥交换
安全性基础 密钥保密性 数学难题(如大整数分解)
典型应用 文件加密、实时通信 密钥交换、数字签名、HTTPS

实际场景中,两者常结合使用:用非对称加密解决对称密钥的安全分发问题,再用对称加密高效处理大量数据传输(如 HTTPS 协议的工作原理)。

cdn怎么实现优化的?

CDN(内容分发网络)通过一系列技术手段和策略实现优化,旨在提升内容分发效率、降低延迟、提高可用性和用户体验。以下是 CDN 优化的关键实现方式:

1. 全球分布式节点部署

CDN 服务商在全球各地部署大量服务器节点(POP,Point of Presence),这些节点靠近用户地理位置。当用户请求内容时,CDN 会将请求导向最近的节点,减少数据传输距离,从而降低延迟。

  • 智能 DNS 解析:根据用户 IP 地址,将请求路由到最近的 CDN 节点。
  • Anycast 技术:多个节点使用相同 IP 地址,通过 BGP 协议选择最优路径。

2. 内容缓存策略

CDN 通过缓存静态内容(如图片、CSS、JS 文件、HTML 页面等)减少源站负载,并加速内容交付:

  • 分层缓存
    • 边缘节点缓存:最接近用户的节点,缓存热门内容。
    • 区域节点缓存:负责服务多个边缘节点,缓存次热门内容。
    • 源站:原始内容存储地,仅在缓存未命中时被访问。
  • 缓存失效策略
    • 时间驱动:设置 TTL(Time-To-Live),过期后重新从源站获取。
    • 事件驱动:源站内容更新时主动推送刷新指令(Purge)到 CDN 节点。

3. 内容优化与压缩

CDN 会对内容进行预处理,提升传输效率:

  • 文件压缩:对文本内容(如 HTML、CSS、JS)进行 gzip 或 Brotli 压缩,减少传输体积。
  • 图片优化
    • 自动转换为更高效的格式(如 WebP)。
    • 按需调整图片质量和尺寸(如响应式图片)。
  • 代码精简:去除不必要的空格、注释,缩短文件大小。
  1. 动态内容加速

针对动态内容(如 API 请求、用户生成内容),CDN 采用特殊优化技术:

  • 动态内容缓存:缓存部分动态内容的片段(如导航栏、广告位)。
  • 协议优化:使用 HTTP/3(基于 QUIC)减少连接延迟,支持多路复用。
  • 边缘计算:在 CDN 节点运行轻量级代码(如 JavaScript),处理部分动态逻辑,减少源站负载。

5. 负载均衡与高可用性

CDN 通过以下方式确保服务稳定和高可用:

  • 多节点冗余:同一区域部署多个节点,避免单点故障。
  • 实时监控与自动切换:监控节点健康状态,自动将流量导向正常节点。
  • DDoS 防护:利用分布式节点分散攻击流量,过滤恶意请求。

6. 预取与预热

  • 内容预取:预测用户可能访问的内容,提前缓存到边缘节点。
  • 内容预热:在流量高峰前,主动将热门内容推送到各节点。

7. 协议与传输优化

  • HTTP/2/3 支持:提升并发性能,减少头部阻塞。
  • TCP 优化:调整 TCP 参数(如初始窗口大小),加速连接建立。
  • QUIC 协议:基于 UDP,减少握手延迟,优化移动网络性能。

8. 安全增强

CDN 通常集成安全功能:

  • HTTPS 支持:提供免费 SSL 证书,加密数据传输。
  • WAF(Web 应用防火墙):过滤 SQL 注入、XSS 等攻击。
  • Bot 管理:识别并拦截恶意爬虫和自动化工具。
  1. 数据分析与智能调度
  • 实时流量分析:根据用户行为和流量模式调整缓存策略。
  • A/B 测试:对比不同节点或配置的性能,优化路由策略。

10. 与源站集成

CDN 与源站紧密协作,确保内容一致性和高效同步:

  • 回源优化:控制回源请求的频率和方式,避免源站过载。
  • 推送机制:源站内容更新时,主动通知 CDN 节点刷新缓存。

示例:CDN 优化前后对比

指标 未使用 CDN 使用 CDN 后
加载时间 5 秒 1.2 秒
全球可用性 98% 99.9%
源站负载
抗 DDoS 能力

总结

CDN 通过分布式架构、缓存策略、内容优化、协议升级和安全增强等多种手段,全面提升内容分发效率和用户体验。选择合适的 CDN 服务商(如 Akamai、Cloudflare、阿里云 CDN 等)并结合业务需求配置优化参数,是实现高效 CDN 的关键。

相关内容

写下自己求职记录也给正在求职得一些建议-CSDN博客

从初中级如何迈入中高级-其实技术只是"入门卷"-CSDN博客

前端梳理体系从常问问题去完善-基础篇(html,css,js,ts)-CSDN博客

前端梳理体系从常问问题去完善-工程篇(webpack,vite)_前端系统梳理-CSDN博客

前端梳理体系从常问问题去完善-框架篇(react生态)-CSDN博客

前端梳理体系从常问问题去完善-框架篇(Vue2&Vue3)-CSDN博客

相关推荐
寻星探路4 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
盟接之桥7 小时前
盟接之桥说制造:引流品 × 利润品,全球电商平台高效产品组合策略(供讨论)
大数据·linux·服务器·网络·人工智能·制造
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端