早鸟文档问题梳理
飞书链接:https://nwy3y7fy8w5.feishu.cn/docx/TIWSdT8RdocYhUxrTFvcSPMfnrY?from=from_copylink 密码:13G@3151
直播间链接:https://appaxba0jjt2374.pc.xiaoe-tech.com/p/t_pc/course_pc_detail/column/p_673ef449e4b0694c950417e7
2.1前端专业知识考查
2.1.1html css
-
盒子模型
-
CSS 盒子模型(Box Model)是网页布局的核心概念之一,它描述了每个元素在页面中所占的空间。每个元素都被视为一个矩形的盒子,这个盒子由四个部分组成:内容区域(content)、内边距(padding)、边框(border) 和 外边距(margin)。
盒子模型的组成部分
-
内容区域(Content):
-
-
这是盒子的核心部分,显示元素的实际内容,比如文本、图片等。
-
可以通过
width
和height
属性设置内容区域的大小。
-
-
内边距(Padding):
-
-
内边距是内容区域与边框之间的空间。
-
可以通过
padding
属性设置内边距的大小。 -
内边距会增加盒子的总大小(除非使用
box-sizing: border-box
)。
-
-
边框(Border):
-
-
边框是围绕内容区域和内边距的边界。
-
可以通过
border
属性设置边框的宽度、样式和颜色。 -
边框也会增加盒子的总大小(除非使用
box-sizing: border-box
)。
-
-
外边距(Margin):
-
-
外边距是盒子与其他元素之间的空间。
-
可以通过
margin
属性设置外边距的大小。 -
外边距不会影响盒子的总大小,但会影响盒子在页面中的位置。
-
-
盒子模型的可视化
+---------------------------+ | Margin | | +---------------------+ | | | Border | | | | +-----------------+ | | | | | Padding | | | | | | +-----------+ | | | | | | | Content | | | | | | | +-----------+ | | | | | +-----------------+ | | | +---------------------+ | +---------------------------+
盒子模型的计算方式
默认情况下,CSS 使用 标准盒子模型(content-box
),盒子总大小的计算公式为:
总宽度 = width + padding-left + padding-right + border-left + border-right 总高度 = height + padding-top + padding-bottom + border-top + border-bottom
例如:
.box {
width: 200px;
height: 100px;
padding: 20px;
border: 10px solid black;
margin: 30px;
}
-
-
内容区域:
200px
(宽) ×100px
(高) -
总宽度:
200 + 20*2 + 10*2 = 260px
-
总高度:
100 + 20*2 + 10*2 = 160px
-
外边距:
30px
(与其他元素的距离)
-
box-sizing
属性
为了更直观地控制盒子的大小,CSS 提供了 box-sizing
属性,可以改变盒子模型的计算方式。
-
content-box
(默认):
-
-
盒子的大小仅包括内容区域。
-
width
和height
只设置内容区域的大小。
-
-
border-box
:
-
-
盒子的大小包括内容区域、内边距和边框。
-
width
和height
设置的是内容区域 + 内边距 + 边框的总大小。
-
-
例如:
.box {
box-sizing: border-box;
width: 200px;
height: 100px;
padding: 20px;
border: 10px solid black;
}
-
-
总宽度和总高度均为
200px
和100px
。 -
内容区域的实际大小会减去内边距和边框:
200 - 20*2 - 10*2 = 140px
(宽),100 - 20*2 - 10*2 = 40px
(高)。
-
外边距折叠(Margin Collapse)
在垂直方向上,相邻元素的外边距可能会发生折叠(合并),取两者中较大的值作为最终的外边距。例如:
<div style="margin-bottom: 20px;">Box 1</div>
<div style="margin-top: 30px;">Box 2</div>
-
-
两个盒子之间的外边距不是
20px + 30px = 50px
,而是30px
(取较大的值)。
-
总结
-
-
盒子模型由内容区域、内边距、边框和外边距组成。
-
默认情况下,盒子的大小是内容区域 + 内边距 + 边框。
-
使用
box-sizing: border-box
可以让盒子的大小包括内容区域、内边距和边框。 -
外边距折叠是垂直方向上相邻元素外边距的合并现象。
-
2.prefetch和preload
两个是link标签的rel值,实现功能不同。
特性 | preload | prefetch |
---|---|---|
加载时机 | 立即加载,高优先级 | 空闲时加载,低优先级 |
适用资源 | 当前页面中关键资源 | 未来页面或用户可能需要的资源 |
优先级 | 高优先级 | 低优先级 |
是否必须使用 | 是,资源必须被当前页面使用 | 否,资源可能被后续页面使用 |
典型用途 | 字体、关键 CSS、关键 JavaScript | 下一页资源、用户可能点击的资源 |
3.BFC 的优点和缺点
优点 | 缺点 |
---|---|
避免外边距折叠 | 可能引入额外的样式 |
清除浮动,避免高度塌陷 | 增加渲染复杂度,可能影响性能 |
隔离布局,避免冲突 | 布局可能不够灵活 |
防止文字环绕浮动元素 | 旧版浏览器可能存在兼容性问题 |
2.1.2 js基础
1.对js单线程的理解
关键词:调用栈,任务队列
-
- 单线程:JavaScript 引擎只有一个调用栈(Call Stack),同一时间只能执行一段代码。
- 任务队列:JavaScript 通过事件循环(Event Loop)和任务队列(Task Queue)来处理异步任务。
由于 JavaScript 是单线程的,如果遇到耗时任务(如大量计算或网络请求),会导致页面卡顿,无法响应用户操作。为了解决这个问题,JavaScript 引入了异步编程模型。
异步处理:JavaScript 通过 事件循环(Event Loop) 和 任务队列(Task Queue) 来实现异步任务的处理。
2.Web Workers 和 Service Workers 的区别
特性 | Web Workers | Service Workers |
---|---|---|
用途 | 处理 CPU 密集型任务 | 网络请求拦截、缓存、离线功能 |
生命周期 | 由主线程控制,任务完成后关闭 | 独立运行,即使页面关闭仍可运行 |
DOM 访问 | 无 | 无 |
通信机制 | postMessage 和 onmessage |
postMessage 和事件监听 |
网络请求拦截 | 不支持 | 支持 |
离线功能 | 不支持 | 支持 |
推送通知 | 不支持 | 支持 |
典型场景 | 数据处理、图像处理、加密 | PWA、离线缓存、后台同步 |
浏览器会自行销毁services worker,也可以手动销毁
3.异步事件机制的理解,为什么settimeout和setinterval不精确的问题
(1)首先一个异常场景,当主线程被阻塞的时候,宏任务队列一定会被阻塞
1 console.log("Start"); 2 setTimeout(() => { 3 console.log("Timeout"); 4 }, 1000); 5 6 // 模拟耗时任务 7 for (let i = 0; i < 1e9; i++) {} 8 console.log("End");
(2)当设置延迟为0时,实际的浏览器还是会设置4ms左右的延迟防止频繁调用
(3)系统时钟误差,setTimeout
和 setInterval
依赖于系统时钟,而系统时钟的精度有限。在大多数操作系统中,时钟的最小精度为 10-15ms。这意味着即使设置了 1ms 的延迟,实际延迟可能会更长。
(4)浏览器标签页的节能模式,不活跃页签浏览器会降低 setTimeout
和 setInterval
的执行频率。
(5)累计执行误差
弥补手段:(1)对于动画或高频任务,可以使用 requestAnimationFrame
,它会在每次浏览器重绘前执行回调,提供更高的精确性。
(2)开辟新线程 new Worker
(3)手动修复误差
1 let startTime = Date.now(); 2 function run() { 3 const elapsed = Date.now() - startTime; 4 console.log("Elapsed time:", elapsed); 5 setTimeout(run, 100 - (elapsed % 100)); // 动态调整延迟 6 } 7 run();
(4)高精度计时器 performance.now()
1 const start = performance.now(); 2 setTimeout(() => { 3 const end = performance.now(); 4 console.log("Actual delay:", end - start); 5 }, 100);
4.一切皆对象
“JavaScript 的一切皆是对象” 的真正含义是:
-
原始类型可以通过包装对象表现得像对象。
-
对象类型本身就是对象。
-
函数也是对象。
-
JavaScript 的继承机制基于原型链,所有对象最终都继承自
Object.prototype
。
5.手写apply,call,bind
apply,call区别:call的第二个入参,call是传入n个都传入fn。apply第二个参数是数组。
call实现:
1 Function.prototype.myCall = function(context, ...args) { 2 // 1. 如果 context 为 null 或 undefined,默认指向全局对象(浏览器中是 window) 3 context = context || window; 4 5 // 2. 将当前函数(this)作为 context 对象的一个属性 6 context.fn = this; 7 8 // 3. 调用函数,并传入参数 9 const result = context.fn(...args); 10 11 // 4. 删除临时添加的属性 12 delete context.fn; 13 14 // 5. 返回函数执行结果 15 return result; 16 };
apply实现:主要是参数args的控制
1 Function.prototype.myApply = function(context, args) { 2 // 1. 如果 context 为 null 或 undefined,默认指向全局对象 3 context = context || window; 4 5 // 2. 将当前函数(this)作为 context 对象的一个属性 6 context.fn = this; 7 8 // 3. 调用函数,并传入参数(args 是一个数组) 9 const result = context.fn(...args); 10 11 // 4. 删除临时添加的属性 12 delete context.fn; 13 14 // 5. 返回函数执行结果 15 return result; 16 };
bind实现:主要区别在返回一个函数
这里额外有个api new.target ,用来判断实例是否通过new操作符生成。
-
如果函数是通过
new
调用的,new.target
会指向该函数本身。 -
如果函数是普通调用(即没有使用
new
),new.target
的值为undefined
。 - 如果
bind
的实现不处理new
调用,绑定函数的this
会被强制绑定到context
,从而破坏new
操作符的行为。
1 Function.prototype.myBind = function(context, ...args) { 2 // 1. 保存当前函数(this) 3 const fn = this; 4 5 // 2. 返回一个新的函数 6 return function(...innerArgs) { 7 // 3. 判断是否通过 new 调用 8 if (new.target) { 9 // 如果是 new 调用,忽略 context,直接调用原函数 10 return new fn(...args, ...innerArgs); 11 } else { 12 // 4. 如果不是 new 调用,将 context 绑定到函数 13 return fn.apply(context, [...args, ...innerArgs]); 14 } 15 }; 16 };
6.手写promise,async/await
1 const PENDING = "pending" 2 const FULFULLED = "fulfulled" 3 const REJECTED = "rejected" 4 5 class MyPromise { 6 // 创建promise对象,需要传入一个函数,会立即执行 7 constructor(handle) { 8 try { 9 handle(this.resolve, this.reject) 10 } catch (error) { 11 this.reject(error) 12 } 13 } 14 // promise的状态 15 status = PENDING 16 value = undefined 17 reason = undefined 18 successCallback = [] 19 failCallback = [] 20 21 // 调用resolve或reject方法,会永久改变promise的状态 22 resolve = v => { 23 if (this.status !== PENDING) return 24 this.status = FULFULLED 25 // 保存执行resolve时传入的参数 26 this.value = v 27 // 如果有成功回调,执行then中的第一个回调 28 if (this.successCallback.length !== 0) { 29 this.successCallback.forEach(cb => { 30 cb() 31 }) 32 } 33 } 34 reject = r => { 35 if (this.status !== PENDING) return 36 this.status = REJECTED 37 // 保存执行reject时传入的参数 38 this.reason = r 39 if (this.failCallback.length !== 0) { 40 this.failCallback.forEach(cb => { 41 cb() 42 }) 43 } 44 } 45 // 因为then方法可以实现链式调用,所以then方法的返回值是promise 46 then(successCb, failCb) { 47 // 如果then方法没有传参数,则设置默认函数 48 successCb = successCb ? successCb : value => value 49 failCb = failCb ? failCb : err => { throw err } 50 let p1 = new MyPromise((resolve, reject) => { 51 // 根据promise的状态执行相应的回调 52 if (this.status === FULFULLED) { 53 // 采用异步函数包裹代码,防止获取不到p1 54 setTimeout(() => { 55 try { 56 // 将then方法中的返回值,作为下一个then方法的回调参数 57 let x = successCb(this.value) 58 resolvePromise(x, p1, resolve, reject) 59 } catch (error) { 60 reject(error) 61 } 62 }, 0); 63 } else if (this.status === REJECTED) { 64 // 采用异步函数包裹代码,防止获取不到p1 65 setTimeout(() => { 66 try { 67 // 将then方法中的返回值,作为下一个then方法的回调参数 68 let x = failCb(this.reason) 69 resolvePromise(x, p1, resolve, reject) 70 } catch (error) { 71 reject(error) 72 } 73 }, 0); 74 } else { 75 // 异步的情况 76 // 用数组保存传入的两个回调(用数组的原因是可能执行多次then方法) 77 successCb && this.successCallback.push(() => { 78 setTimeout(() => { 79 try { 80 // 将then方法中的返回值,作为下一个then方法的回调参数 81 let x = successCb(this.value) 82 resolvePromise(x, p1, resolve, reject) 83 } catch (error) { 84 reject(error) 85 } 86 }, 0); 87 }) 88 failCb && this.failCallback.push(() => { 89 setTimeout(() => { 90 try { 91 // 将then方法中的返回值,作为下一个then方法的回调参数 92 let x = failCb(this.reason) 93 resolvePromise(x, p1, resolve, reject) 94 } catch (error) { 95 reject(error) 96 } 97 }, 0); 98 }) 99 } 100 }) 101 return p1 102 } 103 catch(failCb) { 104 return this.then(undefined, failCb) 105 } 106 finally(callback) { 107 return this.then(value => { 108 return MyPromise.resolve(callback()).then(res => value) 109 }, reason => { 110 callback() 111 return MyPromise.resolve(callback()).then(err => { throw err }) 112 }) 113 } 114 115 // 静态方法,直接通过类名调用 116 static resolve(val) { 117 // 如果是传入的参数是promise对象,则直接返回这个promise; 118 // 如果是非promise对象,则包装成promise对象 119 if (val instanceof MyPromise) return val 120 return new MyPromise(resolve => { 121 resolve(val) 122 }) 123 } 124 static all(arr) { 125 return new MyPromise((resolve, reject) => { 126 let newArr = [] 127 // 用于统计新数组的元素 128 let count = 0 129 function update(key, value) { 130 newArr[key] = value 131 count++ 132 if (count === arr.length) resolve(newArr) 133 } 134 arr.forEach((item, i) => { 135 MyPromise.resolve(item).then(value => { 136 update(i, value) 137 }, reason => { 138 reject(reason) 139 }) 140 }) 141 }) 142 } 143 } 144 function resolvePromise(x, p1, resolve, reject) { 145 // 如果then方法的返回值是它本身,则直接抛出异常 146 if (p1 === x) { 147 return reject(new TypeError("Chaining cycle detected for promise #<Promise>")) 148 } 149 150 if (x instanceof MyPromise) { 151 // 如果是promise对象(通过then方法获取成功或者失败时的值) 152 x.then(value => resolve(value), reason => reject(reason)) 153 } else { 154 // 如果是普通值 155 resolve(x) 156 } 157 } 158 159 module.exports = MyPromise
// 待补充 catch,all,race实现
2.1.3网络相关
1.完整的网络请求
一个完整的 HTTP 请求过程
HTTP(HyperText Transfer Protocol)是用于在Web浏览器和服务器之间传输数据的应用层协议。一个完整的HTTP请求过程包括多个步骤,从客户端发起请求到服务器返回响应,涉及多个底层机制和协议。以下是详细的分步解释:
- DNS解析
- 当用户在浏览器中输入一个URL(如http://example.com )时,浏览器首先需要将域名(example.com )转换为对应的IP地址。
- 这个过程通过DNS(Domain Name System)完成。浏览器会向DNS服务器发送查询请求,DNS服务器返回该域名对应的IP地址。
- 建立TCP连接
- 浏览器与目标服务器建立TCP连接。TCP是一种面向连接的协议,确保数据可靠传输。
- 建立连接的过程称为“三次握手”:
- 客户端发送SYN包。
- 服务器回应SYN-ACK包。
- 客户端发送ACK包确认连接。
- 连接成功后,双方可以开始数据传输。
- 发送HTTP请求
- 浏览器通过已建立的TCP连接向服务器发送HTTP请求报文。
- 请求报文包括:
- 请求行:包含方法(如GET、POST)、路径和HTTP版本(如GET /index.html HTTP/1.1)。
- 请求头:包含客户端信息、接受的内容类型、编码、缓存策略等(如Host: example.com, Accept: text/html)。
- 请求体(可选):对于POST等方法,包含发送的数据。
- 服务器处理请求
- 服务器接收到请求后,根据请求的方法和路径进行处理。
- 对于静态资源(如图片、CSS文件),服务器直接返回文件内容。
- 对于动态资源(如PHP脚本、数据库查询),服务器执行相应逻辑,生成HTML或其他格式的响应内容。
- 发送HTTP响应
- 服务器处理完成后,向客户端发送HTTP响应报文。
- 响应报文包括:
- 状态行:包含HTTP版本和状态码(如HTTP/1.1 200 OK)。
- 响应头:包含内容类型、内容长度、缓存策略等(如Content-Type: text/html, Content-Length: 1234)。
- 响应体:包含实际的数据内容(如HTML页面、JSON数据等)。
- 关闭TCP连接
- 在HTTP/1.0中,默认情况下每个请求都会关闭连接。
- 在HTTP/1.1及更高版本中,默认支持持久连接(Keep-Alive),允许多个请求复用同一个TCP连接,减少连接建立的开销。
- 客户端处理响应
- 浏览器接收到响应后,根据内容类型进行处理:
- HTML:解析并渲染页面。
- CSS:应用样式规则。
- JavaScript:执行脚本。
- 图片:显示图像。
- 浏览器可能会缓存部分资源以提高后续加载速度。
- 浏览器接收到响应后,根据内容类型进行处理:
- 释放资源
- 客户端和服务器完成通信后,释放相关的资源和内存。
详细步骤说明
- DNS解析:确保客户端能够找到目标服务器的IP地址。
- TCP三次握手:确保双方通信的可靠性和有序性。
- HTTP请求报文:清晰定义客户端的需求和期望。
- 服务器处理:根据请求类型和内容进行相应的逻辑处理。
- HTTP响应报文:准确传达服务器的处理结果和数据。
- 持久连接:提高多请求场景下的性能。
- 客户端渲染:将服务器返回的数据转化为用户可见的内容。
- 资源管理:确保高效利用网络和系统资源。
2.浏览器的缓存控制
浏览器如何控制缓存:相应的头信息与状态码
浏览器的缓存控制机制是优化网页加载速度和减少服务器负载的重要手段。通过HTTP头信息和状态码,浏览器能够高效地管理和更新缓存资源。以下是详细的步骤解释:
- HTTP头信息的作用
- Cache-Control: 用于指导浏览器如何缓存资源。常见的指令包括:
max-age=<seconds>
:指定资源在浏览器中可以缓存的时间(以秒为单位)。no-cache
:强制浏览器每次请求都与服务器验证资源是否过期。no-store
:禁止浏览器缓存资源。public
:允许任何缓存机制存储资源。private
:仅允许特定用户的缓存存储资源。
- ETag: 提供资源的唯一标识符,帮助浏览器验证资源是否更改。
- Last-Modified: 指定资源的最后修改时间,用于判断资源是否需要更新。
- Expires: 指定资源的过期时间,告诉浏览器在该时间之后不再使用缓存。
- Cache-Control: 用于指导浏览器如何缓存资源。常见的指令包括:
- 状态码的作用
- 200 OK: 表示资源正常返回,浏览器可以正常处理并缓存资源。
- 304 Not Modified: 表示资源未被修改,浏览器可以继续使用本地缓存。
- 404 Not Found: 表示资源不存在,浏览器需要重新请求或显示错误页面。
- 缓存控制流程
- 初次请求:
- 浏览器向服务器发送HTTP GET请求。
- 服务器返回资源,并附带Cache-Control、ETag、Last-Modified等头信息。
- 浏览器根据Cache-Control指令决定是否缓存资源,并记录ETag和Last-Modified信息。
- 后续请求:
- 浏览器检查本地缓存,发现有对应资源且未过,则期直接使用缓存。
- 如果资源已过期或未找到缓存,浏览器再次向服务器发送请求,并携带If-None-Match(包含ETag)或If-Modified-Since(包含Last-Modified)头信息。
- 服务器根据If-None-Match或If-Modified-Since判断资源是否更改:
- 若未更改,返回304状态码,指示浏览器使用缓存。
- 若已更改,返回200状态码及最新资源,浏览器更新缓存。
- 初次请求:
- 实际应用中的优化策略
- 合理设置缓存时间:根据资源类型(如静态资源、动态内容)设置适当的max-age值,平衡缓存有效性和内容更新频率。
- 利用ETag和Last-Modified:结合使用这两个头信息,增强缓存验证的准确性。
- 区分公共和私有资源:对于公共资源(如图片、CSS文件),使用public指令;对于私有资源(如用户个性化内容),使用private指令。
- 定期清理过期缓存:虽然浏览器通常会自动管理缓存,但定期清理可以释放存储空间并减少潜在的安全风险。
- 案例分析
- 静态资源缓存:
- 服务器对图片、JavaScript文件等静态资源设置长缓存时间(如1年)。
- 浏览器首次加载后,后续访问直接使用缓存,显著提高加载速度。
- 动态内容缓存:
- 对于新闻页面、用户个人中心等动态内容,设置较短的max-age值(如5分钟)。
- 结合ETag和Last-Modified,确保内容及时更新。
- 防止缓存冲突:
- 在版本更新时,通过修改文件名或添加版本号(如style.css?v=1.2 )强制浏览器加载最新版本。
- 静态资源缓存:
3.强缓存与协商缓存的区别与应用
强缓存与协商缓存的区别与应用
在Web开发中,缓存机制是优化网站性能的关键环节。HTTP协议提供了两种主要的缓存机制:强缓存和协商缓存。了解这两种机制的区别及其应用场景,有助于开发者更高效地管理资源加载,提升用户体验。
一、强缓存
1. 定义与作用
强缓存是一种直接使用本地缓存而无需与服务器通信的机制。当浏览器检测到资源仍在有效期内时,它会直接从本地缓存中加载资源,而不会向服务器发送请求。这种方式极大地减少了网络延迟,加快了页面加载速度。
2. 实现方式
强缓存主要通过以下HTTP头信息实现:
- Cache-Control
max-age=<seconds>
:指定资源在浏览器中可以缓存的最大时间(以秒为单位)。例如,max-age=3060
表示资源在1小时内有效。public
:表示资源可以被任何缓存(包括中间代理服务器)存储。private
:表示资源只能由用户的浏览器缓存,不能被共享缓存存储。no-cache
:强制浏览器每次请求都与服务器验证资源是否过期。no-store
:禁止任何设备(包括浏览器)存储资源。
- Expires
- 指定资源的过期时间。例如,
Expires: Wed, 21 Oct 2025 07:28:00 GMT
表示资源在指定日期后过期。
- 指定资源的过期时间。例如,
3. 优点
- 减少网络请求:降低服务器负载。
- 加快加载速度:直接从本地加载资源。
- 节省带宽:减少数据传输量。
4. 缺点
- 内容更新延迟:一旦资源过期,必须等待下一次请求才能获取最新内容。
- 版本控制问题:如果资源频繁更新,强缓存可能导致用户看到旧版本。
二、协商缓存
1. 定义与作用
协商缓存是一种浏览器与服务器协作验证资源有效性的机制。浏览器先检查本地缓存中的资源是否有效,若无效则重新下载。这种方式确保了资源的新鲜度,同时减少了不必要的数据传输。
2. 实现方式
协商缓存主要通过以下HTTP头信息实现:
- ETag
- 服务器为每个资源生成一个唯一的标识符(类似于指纹)。当浏览器再次请求时,会发送
If-None-Match
头携带此标识符。
- 服务器为每个资源生成一个唯一的标识符(类似于指纹)。当浏览器再次请求时,会发送
- Last-Modified
- 记录资源的最后修改时间。浏览器再次请求时会发送
If-Modified-Since
头携带此时间。
- 记录资源的最后修改时间。浏览器再次请求时会发送
3. 响应状态码
- 200 OK:资源已更新,返回新内容。
- 304 Not Modified:资源未更新,浏览器使用本地缓存。
4. 优点
- 确保新鲜度:只有在资源更新时才下载新内容。
- 减少数据传输:避免传输未更改的资源。
- 灵活性高:适用于动态内容,如新闻、用户数据等。
5. 缺点
- 增加额外请求:每次请求都需要与服务器协商,增加了延迟。
- 依赖服务器支持:需要服务器正确实现ETag和Last-Modified头。
三、应用场景
1. 强缓存适用场景
- 静态资源:如图片、CSS文件、JavaScript文件等不经常更新的资源。
- 大型文件:如视频、PDF文档等,减少重复下载。
- CDN加速:结合CDN使用,进一步提升加载速度。
2. 协商缓存适用场景
- 动态内容:如新闻页面、用户个人信息等需要及时更新的内容。
- API接口:返回的数据可能频繁变化,需要确保客户端获取最新信息。
- 混合资源:既有静态资源又有动态内容的网站,可以根据资源类型选择不同的缓存策略。
3.WebSocket 与 HTTP 请求的区别
WebSocket 与 HTTP 请求的区别
WebSocket 和 HTTP 是两种不同的网络通信协议,各自适用于不同的场景。以下是它们的主要区别:
1. 协议基础
- HTTP (Hypertext Transfer Protocol):
- 基于请求-响应模式。
- 每次客户端(如浏览器)发送请求,服务器必须回复响应。
- 无状态:每次请求都是独立的,服务器不保留客户端上下文。
- WebSocket:
- 基于 TCP 协议。
- 建立持久连接后,客户端和服务器可以双向通信。
- 有状态:连接保持打开状态,适合实时通信。
2. 连接方式
- HTTP:
- 每次请求都需要重新建立连接。
- 使用不同的端口(默认为 80 和 443)。
- WebSocket:
- 建立一次连接后,可以在同一连接上进行多次数据传输。
- 使用统一的端口(默认为 80 和 443)。
3. 数据传输效率
- HTTP:
- 每次请求都需要携带大量的头部信息。
- 不适合频繁的小规模数据传输。
- WebSocket:
- 连接建立后,后续数据传输的头部信息极小。
- 适合实时、高效的数据传输。
4. 适用场景
- HTTP:
- 适用于传统的Web页面加载。
- 适合获取静态资源(如图片、CSS 文件等)。
- 支持多种 HTTP 方法(如 GET、POST、PUT、DELETE 等)。
- WebSocket:
- 适用于需要实时通信的场景。
- 如即时聊天、在线游戏、实时股票市场数据推送。
- 支持双向通信,适合需要服务器主动推送数据的场景。
5. 安全性
- HTTP:
- 明文传输,容易被窃听。
- 可以通过 HTTPS(SSL/TLS 加密)保证数据安全。
- WebSocket:
- 使用 WSS(WebSocket Secure)进行加密通信。
- 提供与 HTTPS 类似的加密保护。
6. 可靠性
- HTTP:
- 每次请求都有明确的响应。
- 支持重传机制(如超时重试)。
- WebSocket:
- 连接建立后,依赖于底层 TCP 协议的可靠性。
- 如果连接中断,需要重新建立连接。
7. 开发与实现
- HTTP:
- 广泛支持,几乎所有Web服务器都支持HTTP。
- 开发简单,使用标准的 API(如 fetch、XMLHttpRequest)即可实现。
- WebSocket:
- 需要服务器和客户端都支持 WebSocket 协议。
- 在 Node.js 中常用的库有 Socket.io 和 Express WebSocket 插件。
8. 性能对比
- HTTP:
- 不适合高频率的数据交换。
- 每次请求都有较高的开销。
- WebSocket:
- 更适合需要持续数据交换的场景。
- 数据传输延迟较低。
2.1.4 浏览器相关
1.渲染流程
进程和线程相关 :https://segmentfault.com/a/1190000012925872#item-1
渲染相关:https://blog.csdn.net/weixin_45811256/article/details/130316442
2.1.5安全相关
前端安全中需要注意的问题
- 输入验证:对用户输入的数据进行严格的验证和过滤,防止恶意输入导致的安全漏洞。
- 跨站脚本攻击(XSS):防止用户输入的脚本在其他用户的浏览器上执行。
- 跨站请求伪造(CSRF):防止攻击者利用用户的认证状态发起非授权请求。
- 敏感信息保护:确保用户敏感信息(如密码、信用卡号等)不被泄露或篡改。
- 内容安全策略(CSP):配置CSP头,限制页面可以加载的资源来源,防止脚本注入。
- HTTP标头安全:设置安全的HTTP标头,如
X-Content-Type-Options
、X-Frame-Options
等。 - 防止点击劫持:使用
X-Frame-Options
头防止页面被嵌入到其他网站的iframe中。 - 会话管理:确保会话令牌的安全性,避免会话固定(Session Fixation)等攻击。
- 防止敏感信息泄露:避免在URL、Cookie中明文传输敏感信息。
- 第三方库的安全性:定期更新第三方库,防止已知漏洞被利用。
XSS/CSRF 攻击的过程及防范
XSS(跨站脚本攻击)
- 攻击过程:
- 攻击者向网页注入恶意脚本(如JavaScript)。
- 其他用户访问该页面时,脚本在他们的浏览器中执行。
- 脚本可能窃取用户Cookie、Session ID或其他敏感信息。
- 防范措施:
- 输入过滤:对用户输入进行严格的HTML转义和验证。
- 输出编码:在渲染用户输入时进行HTML编码。
- 使用CSP:配置内容安全策略,限制脚本的执行来源。
- HTTPOnly和Secure标志:设置Cookie的
HttpOnly
和Secure
标志,防止脚本窃取Cookie。 - 使用安全框架:如React、Vue等框架内置的XSS防护机制。
CSRF(跨站请求伪造)
-
攻击过程:
- 攻击者诱使用户点击一个链接或访问一个恶意页面。
- 用户在不知情的情况下,使用其认证状态(如Cookie)发送非授权请求。
- 攻击者利用用户的权限执行恶意操作(如转账、修改密码等)。
-
防范措施:
- CSRF Token:在表单中添加随机Token,并验证请求中的Token是否有效。
- Referer检查:检查请求来源是否合法,但此方法不可靠,因为Referer头可以被伪造。
- SameSite Cookie标志:设置Cookie的
SameSite
属性,限制跨站请求中Cookie的发送。 - 验证请求来源:通过IP地址、User-Agent等信息验证请求来源。
- 使用安全协议:确保所有请求通过HTTPS传输,增加攻击难度。
其他网络安全相关问题
-
点击劫持(Clickjacking):
- 攻击者通过隐藏iframe或CSS层叠技术,诱导用户点击看似无害的按钮,实际触发恶意操作。
- 防范措施:设置
X-Frame-Options
头,禁止页面被嵌入到其他网站的iframe中。
-
敏感信息泄露:
- 攻击者通过SQL注入、XSS等手段窃取用户的敏感信息(如密码、信用卡号等)。
- 防范措施:加密存储敏感信息,避免在URL、Cookie中明文传输。
-
会话固定(Session Fixation):
- 攻击者固定用户的会话ID,从而冒充用户身份。
- 防范措施:在用户登录后重新生成新的Session ID。
-
不安全的反序列化(Insecure Deserialization):
- 攻击者通过反序列化恶意数据,导致代码执行或拒绝服务。
- 防范措施:避免直接反序列化不可信的数据,使用安全的序列化格式。
-
服务器端模板注入(Server-Side Template Injection):
- 攻击者通过注入恶意模板代码,控制服务器端的渲染逻辑。
- 防范措施:对用户输入进行严格的过滤和验证,避免动态加载不可信的模板。
SQL注入和命令行注入
SQL注入
- 攻击过程:
- 攻击者通过构造恶意SQL语句,注入到应用程序的数据库查询中。
- 数据库执行恶意查询,可能导致数据泄露、篡改或删除。
- 防范措施:
- 使用ORM框架:如Hibernate、Entity Framework等,减少直接拼接SQL的风险。
- 参数化查询:使用PreparedStatement等预编译机制,避免动态拼接SQL。
- 输入过滤:对用户输入进行严格的SQL字符过滤(如单引号、双引号、
--
等)。 - 最小权限原则:数据库账户仅具有必要的权限,限制潜在的破坏范围。
命令行注入
- 攻击过程:
- 攻击者通过构造恶意命令,注入到应用程序的命令行执行函数中。
- 系统执行恶意命令,可能导致文件删除、权限提升甚至系统崩溃。
- 防范措施:
- 避免动态拼接命令:使用参数化API代替动态拼接命令字符串。
- 输入过滤:对用户输入进行严格的命令字符过滤(如
|
、&
、;
等)。 - 限制程序权限:确保程序以最低权限运行,减少攻击者的操作空间。
DDoS攻击
- 定义:分布式拒绝服务攻击(DDoS)是指攻击者通过大量请求或数据包淹没目标服务器,使其无法正常提供服务。
- 常见类型:
- 体积型攻击:通过发送大量垃圾流量耗尽目标带宽(如UDP Flood、DNS放大攻击)。
- 协议型攻击:利用TCP/IP协议栈的缺陷,耗尽服务器资源(如SYN Flood、ACK Flood)。
- 应用层攻击:针对Web应用发起大量合法或半合法的请求,耗尽服务器资源(如HTTP Flood)。
- 防范措施:
- 使用CDN加速和流量清洗服务。
- 配置防火墙规则,过滤异常流量。
- 启用限流机制,限制单位时间内来自同一IP的请求次数。
流量劫持
- 定义:流量劫持是指攻击者通过控制网络路径或篡改数据包,窃取或篡改用户的数据流量。
- 常见方式:
- DNS劫持:篡改DNS解析结果,将用户引导至恶意网站。
- 中间人攻击(MITM):在通信双方之间插入中间设备,窃取或篡改数据。
- ARP欺骗:在局域网内伪造ARP报文,窃取用户的网络流量。
- 防范措施:
- 使用HTTPS协议加密数据传输。
- 配置DNSSEC,防止DNS劫持。
- 在局域网内启用DHCP Snooping和动态ARP检测(DAI)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!