进程与线程
- 进程是操作系统资源分配的基本单位,进程中包含线程。
- 线程是由进程所管理的。为了提升浏览器的稳定性和安全性,浏览器采用了多进程模型。
从输入URL到浏览器显示页面发生了什么?
- 浏览器查找当前URL是否存在缓存,如果有缓存、并且缓存未过期,直接从缓存中返回
- 查看域名是否已经被解析过了,没有解析过进行DNS解析将域名解析成IP地址,并增加端口号
- 如果请求是HTTPS,进行SSL协商
- 利用IP地址进行寻址
- 服务器创建TCP链接 (三次握手)
- 服务器响应结果
渲染流程
- 需要将HTML转化成DOM树
- CSS进行解析,解析成styleSheets
- 计算出DOM树中每个节点的具体样式
- 创建渲染(布局)树,并计算节点渲染到页面的坐标位置
- 通过布局树,进行分层 (根据定位属性、透明属性、transform属性、clip属性等)生产图层树
- 将不同图层进行绘制,转交给合成线程处理。最终生产页面,并显示到浏览器上
网络优化策略
- 减少HTTP请求数,合并JS、CSS,合理内嵌CSS、JS
- 合理设置服务端缓存,提高服务器处理速度。 (强制缓存、对比缓存)
- 避免重定向,重定向会降低响应速度 (301,302)
- 使用dns-prefetch,进行DNS预解析
- 采用域名分片技术,将资源放到不同的域名下。接触同一个域名最多处理6个TCP链接问题。
- 采用CDN加速加快访问速度
- gzip压缩优化 对传输资源进行体积压缩 (html,js,css)
- 加载数据优先级 : preload(预先请求当前页面需要的资源) prefetch(将来页面中使用的资源) 将数据缓存到HTTP缓存中
<link rel="preload" href="style.css" as="style">
关键渲染路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjiQHWrn-1631675666598)
减少回流和重绘
静态文件优化
图片优化
图片格式:
- jpg:适合色彩丰富的照片、banner图;不适合图形文字、图标(纹理边缘有锯齿),不支持透明度
- png:适合纯色、透明、图标,支持半透明;不适合色彩丰富图片,因为无损存储会导致存储体积大
- gif:适合动画,可以动的图标;不支持半透明,不适和存储彩色图片
- webp:适合半透明图片,可以保证图片质量和较小的体积
- svg格式图片:相比于jpg和jpg它的体积更小,渲染成本过高,适合小且色彩单一的图标;
图片优化:
- 避免空src的图片
- 减小图片尺寸,节约用户流量
- img标签设置alt属性, 提升图片加载失败时的用户体验
- 原生的loading:lazy 图片懒加载
- 不同环境下,加载不同尺寸和像素的图片
- 对于较大的图片可以考虑采用渐进式图片
- 采用base64URL减少图片请求
- 采用雪碧图合并图标图片等
HTML优化
- 语义化HTML:代码简洁清晰,利于搜索引擎,便于团队开发
- 提前声明字符编码,让浏览器快速确定如何渲染网页内容
- 减少HTML嵌套关系、减少DOM节点数量
- 删除多余空格、空行、注释、及无用的属性等
- HTML减少iframes使用 (iframe会阻塞onload事件可以动态加载iframe)
- 避免使用table布局
CSS优化
- 减少伪类选择器、减少样式层数、减少使用通配符
- 避免使用CSS表达式,CSS表达式会频繁求值, 当滚动页面,或者移动鼠标时都会重新计算 (IE6,7)
background-color: expression( (new Date()).getHours()%2 ? "red" : "yellow" );
- 删除空行、注释、减少无意义的单位、css进行压缩
- 使用外链css,可以对CSS进行缓存
- 添加媒体字段,只加载有效的css文件
<link href="index.css" rel="stylesheet" media="screen and (min-width:1024px)" />
- CSS contain属性,将元素进行隔离
- 减少@import使用,由于@import采用的是串行加载
JS优化
- 通过async、defer异步加载文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vWRtHSKm-1631675666602)
- 减少DOM操作,缓存访问过的元素
- 操作不直接应用到DOM上,而应用到虚拟DOM上。最后一次性的应用到DOM上。
- 使用webworker解决程序阻塞问题
- IntersectionObserver
const observer = new IntersectionObserver(function(changes) {
changes.forEach(function(element, index) {
if (element.intersectionRatio > 0) {
observer.unobserve(element.target);
element.target.src = element.target.dataset.src;
}
});
});
function initObserver() {
const listItems = document.querySelectorAll('img');
listItems.forEach(function(item) {
observer.observe(item);
});
}
initObserver();
- 虚拟滚动 vertual-scroll-list
- requestAnimationFrame、requestIdleCallback
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R96wpPZL-1631675666607)
- 尽量避免使用eval, 消耗时间久
- 使用事件委托,减少事件绑定个数。
- 尽量使用canvas动画、CSS动画
字体优化
@font-face {
font-family: "Bmy";
src: url("./HelloQuincy.ttf");
font-display: block;
/* block 3s 内不显示, 如果没加载完毕用默认的 */
/* swap 显示老字体 在替换 */
/* fallback 缩短不显示时间, 如果没加载完毕用默认的 ,和block类似*/
/* optional 替换可能用字体 可能不替换*/
}
body {
font-family: "Bmy"
}
FOUT(Flash Of Unstyled Text) 等待一段时间,如果没加载完成,先显示默认。加载后再进行切换。
FOIT(Flash Of Invisible Text)字体加载完毕后显示,加载超时降级系统字体 (白屏)
优化策略
- 关键资源个数越多,首次页面加载时间就会越长
- 关键资源的大小,内容越小,下载时间越短
- 优化白屏:内联css和内联js,移除文件下载,减小文件体积
- 预渲染,打包时进行预渲染
- 使用SSR加速首屏加载(耗费服务端资源),有利于SEO优化。 首屏利用服务端渲染,后续交互采用客户端渲染
浏览器的存储
- cookie: cookie过期时间内一直有效,存储大小4k左右、同时限制字段个数,不适合大量的数据存储,每次请求会携带cookie,主要可以利用做身份检查。
- 设置cookie有效期
- 根据不同子域划分cookie较少传输
- 静态资源域名和cookie域名采用不同域名,避免静态资源访问时携带cookie
- localStorage: chrome下最大存储5M, 除非手动清除,否则一直存在。利用localStorage存储静态资源
- sessionStorage: 会话级别存储,可用于页面间的传值
- indexDB:浏览器的本地数据库 (基本无上限)
浏览器的事件机制
关键词:事件捕获、事件冒泡、DOM Level 0事件、DOM Level 2事件
事件流
JS 与 HTML 的交互是用事件实现的。事件流描述了页面接收事件的顺序。
事件冒泡
事件冒泡是从最具体的元素开始触发事件,然后向上传播至没有那么具体的元素(或文档)。
事件捕获
事件捕获是从最不具体的节点最先接收事件,向下传播至最具体的节点。事件捕获实际上是为了在事件到达最终目标前拦截事件。
旧版本浏览器不支持事件捕获。
DOM 事件流
DOM2 Events 规范规定事件流分为 3 个阶段: 事件捕获、到达目标 和 事件冒泡。
只有 IE8 以及更早的浏览器不支持
事件处理程序
为了响应用户或者浏览器执行的某种动作( click
、 load
、 mouseover
… )而调用的 on 开头的函数被称为事件处理程序(事件监听器)。
HTML 事件处理程序
特定的元素支持的每个事件都可以用 HTML 属性的形式使用事件处理程序。其实也就是我们最常使用的方式,如下代码, onclick
属性的值是 JS 代码或者其他的调用方法。
使用事件监听器,浏览器会先创建一个函数来封装属性的值,这个函数有一个特殊的局部变量:event
用来保存 event
对象,事件处理函数中的 this
指向事件的目标元素。。
<input type="button" value="click me" onclick="console.log('click')" />
DOM0 事件处理程序
在 JavaScript 中创建事件监听器的传统方式是把一个函数赋值给 DOM 元素。兼容性最好,所有的浏览器都支持此方法。
每个元素(包括 window 和 document)都有事件处理程序的属性(一般都 onxxxx),这个属性的值为一个函数。
const btn = document.getElementById("myBtn");
btn.onclick = function(){
console.log('Clicked')
}
DOM0 事件处理是发生在程序赋值时注册在事件流的冒泡阶段的。
所赋值的函数被视为元素的方法,在元素的作用域中运行,this 指向该元素本身。在事件处理程序中通过 this 可以访问元素的任何属性和方法。
将事件处理程序属性设置为 null,即可移除通过 DOM0 方式添加的事件处理程序。
btn.onclick = null;
如果有多个 DOM0 事件处理程序的话,后面的是会把前面的给覆盖掉。只有执行最后一个调用的结果。
DOM2 事件处理程序
我们也可以通过在所有的 DOM 节点上通过 addEventListener()
和 removeEventLinstener()
来添加和移除事件处理程序。
addEventListener()` 和 `removeEventLinstener()` 接收 3 个参数:事件名、事件处理函数 和 一个 option 对象或一个布尔值 `useCapture`( `true` 表示在捕获阶段调用事件处理程序, `false` (默认值)表示在冒泡阶段调用事件处理程序,因为跨浏览器兼容性好,所以事件处理程序默认会被添加到事件流的冒泡阶段(也就是默认最后一个参数为 `false` ))。 `addEventListener(type, listener, useCapture | options)
option 参数有一下几个选择
capture: Boolean,表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。
once: Boolean,表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除。
passive: Boolean,设置为true时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。
useCapture 参数如下
useCapture 可选
Boolean,在DOM树中,注册了listener的元素, 是否要先于它下面的EventTarget,调用该listener。 当useCapture(设为true) 时,沿着DOM树向上冒泡的事件,不会触发listener。当一个元素嵌套了另一个元素,并且两个元素都对同一事件注册了一个处理函数时,所发生的事件冒泡和事件捕获是两种不同的事件传播方式。事件传播模式决定了元素以哪个顺序接收事件。进一步的解释可以查看 事件流 及 JavaScript Event order 文档。 如果没有指定, useCapture 默认为 false 。
useCapture( option 中的 capture 也是一样)只是控制该事件处理程序是添加在事件流的捕获阶段还是冒泡阶段,对事件的传播是没有影响的!
IE 事件处理程序
IE 实现事件处理程序的方法是: attachEvent()
和 detachEvent()
这两个方法接收两个同样的参数:事件处理程序的名称( eg: onclick
)和事件处理函数。因为 IE8 及更早的版本只支持事件冒泡,所以使用 attachEvent()
添加的事件处理程序是添加在冒泡阶段。
const btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
console.log("Clicked");
})
IE 事件处理程序和 DOM2 事件处理程序有两个不一样的地方
- 作用域:
attachEvent()
是在全局作用域中运行的,所以attachEvent()
中的函数中的this
是window
; - 执行顺序:IE 事件处理程序的执行顺序是和添加顺序相反的
四种事件处理程序的区别
使用方法 | 移除方法 | 备注 | |
---|---|---|---|
HTML 事件处理程序 | 用 HTML 属性的形式使用事件处理程序 onclick="console.log('click')" | 同 DOM0 事件处理程序 方式 | event 局部变量用来保存 event 对象,this 指向事件的目标元素 |
DOM0 事件处理程序 | 把一个函数赋值给 DOM 元素 btn.onclick = function(){} | btn.onclick = null | 1. 发生在冒泡阶段 2. this 指向元素本身3. event 局部变量用来保存 event 对象,事件的目标元素 |
DOM2 事件处理程序 | addEventListener() | removeEventLinstener() | 1. 接收 3 个参数:事件名、事件处理函数 和 options 或一个布尔值( true 表示在捕获阶段调用事件处理程序,false (默认值)表示在冒泡阶段调用事件处理程序)2. 可以给一个元素添加多个事件处理程序,并按添加的顺序触发。 3. 使用 addEventListener() 添加的事件处理程序只能使用 removeEventLinstener() 移除(三个参数一致才可以)4. this 和event 同DOM0 |
IE 事件处理程序 | attachEvent() | detachEvent() | 1. IE8 及更早的版本只支持事件冒泡 2. attachEvent()是在全局作用域中运行的, this 是 window 3. IE 事件处理程序的执行顺序是和添加顺序相反的 4. event 对象是全局对象 window 的一个属性 |
Cookie
简介
主要为了辨别用户身份而储存在用户本地终端上的数据
可以记录用户对网站的访问情况(停留时长,访问深度,记录账号密码,在线状态等)
主要由服务端生成然后下发,客户端也可控制其内容
每次发送请求都会自动携带对应域名的cookie
如何使用
服务端
服务端在响应头(Response Header)中添加一个Set-Cookie
字段
示例
Set-Cookie:"name=value;expires=session;path=/;domain=.sugarat.top;HttpOnly;secure;sameSite=lax"
客户端(浏览器)
document.cookie
可以通过此 API获取或者修改cookie
Set-Cookie
Set-Cookie 字段的属性介绍
cookie属性 | 简介 | 特殊说明 |
---|---|---|
name | 键 | - |
value | 值 | - |
Expires | 过期时间 | 一个固定的时间 |
Max-Age | 过期时间 | 收到此cookie后多久后过期,优先级大于Expires |
Domain | 可以送达的主机名(域名) | - |
path | 生效路径 | 路径必须出现在要请求的资源的路径中才可以发送 |
Secure | 安全标志 | 只有使用HTTPS协议的时候才会携带此cookie |
HTTPOnly | 安全标志 | 不允许使用脚本去更改/获取这个cookie |
SameSite | 安全标志 | 控制跨站请求获取cookie |
属性补充说明
- Expires:其值为默认session,即关闭浏览器时此cookie就过期失效
- Max-Age:不同取值范围不同效果
- 大于0:会将cookie存到本地文件中
- 等于0:立即删除
- 小于0:等价于会话性cookie
- 优先级大于Expires
- Domain:指定了 Cookie 可以送达的主机名
- 没有指定:默认值为当前文档访问地址中的主机部分(不包含子域名)
- 如果设置为
.a.com
那么a.com
,a.a.com
,b.a.com
等都能访问,即a.com
的子域名都可以访问到这个cokie
- HTTPOnly
- 防止客户端脚本通过
document.cookie
方式访问或者更改 此Cookie - 有助于避免 XSS 攻击
- 防止客户端脚本通过
- SameSite:可以设置让 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)
- Strict:仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,当前网页 URL 与请求目标 URL 完全一致才发送
- Lax:允许部分(导航到目标网址的 Get 请求)第三方请求携带 Cookie
- None:无论是否跨站都会发送 Cookie
- 低版本Chrome中默认值是 None ,在Chrome稳定版80及更高版本上默认是 Lax
SameSite = lax 的影响
Set-Cookie:'name=value;SameSite=Lax;'
大多数情况不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外
- 超链接
- GET表单
- 预加载请求
请求类型 | 示例 | SameSite = lax 是否发送cooie |
---|---|---|
超链接 | ✅ | |
GET表单 | ✅ | |
预加载 | ✅ | |
POST 表单 | ❌ | |
image | ❌ | |
iframe | ❌ | |
ajax | fetch(url) | ❌ |
Cookie 的作用域
Domain 和 Path 标识共同定义了 Cookie 的作用域:即哪些URL的请求 会携带 目标Cookie
用途
- 会话状态管理:(如用户登录状态、账号信息等)
- 个性化设置:(如用户自定义设置、主题等)
- 用户行为分析:埋点系统(访问深度,停留时长等)
缺点
- 容量问题:有上限,最大只能有 4KB
- 性能问题:同一个域名下的所有请求,都会携带 Cookie,某些请求(a,img,link等标签发出的请求)可能不需要此cookie,会加大传输的头部,损耗一定时空开销
- 安全问题:客户端可以通过一定手段(脚本,devtools,本地存储的文件,修改host文件)获取到,存在XSS,CSRF等安全问题
解决安全问题的方案
- 减短cookie的有效时间
- 添加HttpOnly属性:防止本地脚本读取cookie
- 服务端对传送的cookie加密
- 添加Secure属性:使用https协议传输
- 设置samesite属性为需要的值:严格卡控cookie的携带范围
如何删除一个cookie
document.cookie = 'user=jeskson;expires='+new Date(0); // user是cookie的key
localStorage与sessionStorage
浏览器提供的数据存储API,作用相同,生命周期与作用域的不同
window.sessionStorage.setItem()
window.localStorage.setItem()
window.sessionStorage.getItem()
window.localStorage.getItem()
生命周期
- localStorage 是持久化的本地存储,永远不会过期,除非手动删除
- sessionStorage 是临时性的本地存储,在会话结束时(关闭页面),存储的内容就被释放
作用域
Local Storage
、Session Storage
和 Cookie
都遵循同源策略
但Session Storage有特殊之处:即便是相同域名下的两个页面,只要它们不在浏览器的同一个Tab中打开,那么它们的 Session Storage 内容便无法共享
优点
- 存储容量大:不同浏览器,存储容量可以达到 5-10M,针对一个域名
- 存储于客户端,不会服务端发生通信
缺点
- 只能存储字符串,JSON对象需要转换为json string 存储
- 只适用于存储少量简单数据
- localStorage需要手动删除
应用场景
- base64图片存储:存储logo
- 接口数据持久化:对于依赖于接口(变动周期比较长)生成的内容,可以使用storage存储,以加快首屏渲染
IndexedDB
运行在浏览器上的非关系型数据库
依旧受同源策略限制
优点
- 理论上没有存储上线
- 可以存储字符串,还可以存储二进制数据
- 浏览器提供了一套可简单操作的API
应用场景
- 当数据的复杂度和规模上升到了 LocalStorage 无法解决的程度,就使用IndexDB
- 临时存储复杂的数据,如页面中的临时文章
- 一些复杂表单内容的离线保存
使用教程
口诀:
(1)一个语言:不管是WebSQL还是MySQL,SQL的语法必须掌握。SQL是一个结构化查询语言,说白就是用来查询数据的语言中是最自然、最简洁的。
(2)三个函数:分别是:
A. openDatabase 创建或打开一个本地的数据库对象
B. executeSql 执行SQL语句,在回调函数的参数中获取执行结果
C. transaction 处理事务,当一条语句执行失败的时候,之前的执行全部失效
SQL:
(1)概述:
以下只是把每个功能对应的最基本的SQL语句过一遍。如果不会SQL的,仅做简单语法参考,有兴趣的童鞋需要找资料系统性地全面学习。
(2)创建数据表:
创建具有多个列,每个列用于存放可不同类型的数据。有列自然有行的概念,行代表一组数据,每组数据是当行对应的多个列的数据集合。
CREATE TABLE IF NOT EXISTS 表名(列名称1 数据类型, 列名称2 数据类型, 列名称N 数据类型)
(3)查询数据:
从某表中查询某行某列的数据或查询表中所有元素。
SELECT 列名称1,列名称2,列名称3 FROM 表名称 WHERE 某列名 = 某值
(4)插入数据:
向某表中插入行数据,行中每个值对应列名。
INSERT INTO 表名(列名称1, 列名称2, 列名称N) VALUES (值1, 值2, 值N)
(5)更新数据:
更新某行中列的值。
UPDATE 表名 SET 列名称1=新值, 列名称2=新值, 列名称N=新值 WHERE 某列名 = 某值
(6)删除数据:
删除某行,否则删除所有数据。
DELETE FROM 表名 WHERE 列名称 = 值
Web SQL本地存储的三个函数:
(1)openDatabase (数据库名字, 数据库版本号, 显示名字, 数据库保存数据的大小, 回调函数(可选))
不过是否一脸懵逼,好奇怪是不是,参数还要写版本号,还有,显示名字什么鬼?不过,经过测试后,我都是直接这样写就是了(大小请自己定),如下:
var db = openDatabase("MyDatabase", "", "My Database", 1024*1024);
(2)executeSql(查询字符串, 用以替换查询字符串中问号的参数, 执行成功回调函数(可选), 执行失败回调函数(可选))
参数一自然是SQL语句,其中值数据可用?代替;参数二是SQL语句中?对应的值(很像PDO的预处理)。注意,executeSql不能单独使用,需要在事务transaction函数下使用。例子如下:
executeSql("CREATE TABLE IF NOT EXISTS MyData(name TEXT,message TEXT,time INTEGER)");
(3)transaction(包含事务内容的一个方法, 执行成功回调函数(可选), 执行失败回调函数(可选))
事务内容为一个或多个executeSql函数构成。这个函数很难用语言表达,所以请看例子:
db.transaction(function(tx){
tx.executeSql("CREATE TABLE IF NOT EXISTS MyData(name TEXT,message TEXT,time INTEGER)", [], function(){ alert("create ok")});
tx.executeSql("SELECT * FROM MyData", [], function(){alert("select ok")});
tx.executeSql("DROP TABLE IF EXISTS MyData", [], function(){alert("drop ok")});
});
缓存机制
浏览器第一次向服务器发送请求后拿到结果,会根据响应报文中的HTTP头的缓存标识决定是否缓存结果,是则将结果和缓存标识存入浏览器缓存中。
强制缓存
- 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致)
- 存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存
- 存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果
当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。
Expires:Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。到了HTTP/1.1,Expire已经被Cache-Control替代,原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义。
Cache-Control:在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control的默认取值
- no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
内存缓存(from memory cache)和硬盘缓存(from disk cache):
- 内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
- 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
- 时效性:一旦该进程关闭,则该进程的内存则会清空。
- 硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。
协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
- 协商缓存生效,携带缓存标识发起HTTP请求,资源无更新,返回304,获取该请求的浏览器缓存;
- 协商缓存失效,携带缓存标识发起HTTP请求,资源有更新,返回200和请求结果结果,并将结果和缓存标识写入浏览器缓存
协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag 和 If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。
服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。
服务器收到该请求后,发现该请求头中含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200。
强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存
HTTP 常用的状态码及使用场景?
- 1xx:表示目前是协议的中间状态,还需要后续请求
- 2xx:表示请求成功
- 3xx:表示重定向状态,需要重新请求
- 4xx:表示请求报文错误
- 5xx:服务器端错误
常用状态码:
- 101 切换请求协议,从 HTTP 切换到 WebSocket
- 200 请求成功,有响应体
- 301 永久重定向:会缓存
- 302 临时重定向:不会缓存
- 304 协商缓存命中
- 403 服务器禁止访问
- 404 资源未找到
- 400 请求错误
- 500 服务器端错误
- 503 服务器繁忙
HTTP 常用的请求方式,区别和用途?
http/1.1 规定如下请求方法:
- GET:通用获取数据
- HEAD:获取资源的元信息
- POST:提交数据
- PUT:修改数据
- DELETE:删除数据
- CONNECT:建立连接隧道,用于代理服务器
- OPTIONS:列出可对资源实行的请求方法,常用于跨域
- TRACE:追踪请求-响应的传输路径
计算机网络的认识
应用层、表示层、会话层、传输层、网络层、数据链路层、物理层