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

前言

对于网络,也做了一下问题得整理,估计后面会写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. 动态内容缓存
  • 使用

    头指定根据请求头(如

    sql 复制代码
    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 响应头

    javascript 复制代码
    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

    sql 复制代码
    Accept-Language

    css 复制代码
    Content-Language

    ),或

    css 复制代码
    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博客

相关推荐
excel3 小时前
🌿 一文看懂 Vue 3 的 watch 源码:从原理到流程
前端
繁依Fanyi4 小时前
让工具说话:我在 Inspira Board 里用 AI 把“能用、好用、可复用”落成了日常
前端
weixin_456904274 小时前
C# 中的回调函数
java·前端·c#
kura_tsuki5 小时前
[Web网页] LAMP 架构与环境搭建
前端·架构
yinuo5 小时前
UniApp+Vue3多分包引入同一 npm 库被重复打包至 vendor 的问题分析与解决
前端
码界奇点5 小时前
Spring Web MVC构建现代Java Web应用的基石
java·前端·spring·设计规范
yinuo5 小时前
UniApp + Vue3 使用 marked 报错:SyntaxError /[\p{L}\p{N}]/u 问题分析与解决
前端
绝无仅有5 小时前
某大厂跳动Java面试真题之问题与解答总结(二)
后端·面试·github
绝无仅有5 小时前
某大厂跳动Java面试真题之问题与解答总结(三)
后端·面试·架构