css3新特性
- 圆角效果;
- 图形化边界;
- 块阴影与文字阴影;
- 使用RGBA实现透明效果;
- 渐变效果;
- 使用“@Font-Face”实现定制字体;
- 多背景图;
- 文字或图像的变形处理;
- 多栏布局;
- 媒体查询等。
模块化开发
1. 概念
- 在Web开发中,通常将项目的实现划分成许多模块。模块化开发其实就是将功能相关的代码封装在一起,方便维护和重用。另外,模块之间通过API进行通信。各个模块的命名空间独立,就不会变量被污染。(模块的依赖关系,通过模块管理工具(如 webpack、 require.js等)进行管理。)
2. AMD与CMD的区别是什么?
- 异步模块定义(AMD)规范是 require. js推广的、对模块定义的规范。
- 通用模块定义(CMD)规范是 SeaJS推广的、对模块定义的规范。
- 对于依赖的模块,AMD提前执行,CMD延迟执行,不过 require.JS从2.0版本开始,也改成可以延迟执行(根据写法不同,处理方式不同)。
- CMD推崇依赖就近,AMD推崇依赖前置。
EsModule CommonJs
1. 目的:
- 解决全局变量污染
- 解决依赖混乱
- 更容易细分文件
2. 导入导出方式
-
commonJs: 是一个社区规范,出现的时间较早,目前仅node环境支持,
- 导入: 函数require("要导入的模块路径"),可以省略.js,必须以./或../开头
- 有缓存: 一个模块在被导入时会运行一次,node会缓存导出结果,重新导入时不会再运行该模块
- 导出: 在模块中给module.exports赋值,赋什么类型则导出什么类型
-
Es Module: ES6发布的官方模块化标准,目前浏览器和新版本node环境均支持
- 导入: 使用关键字import,同时可以更改导入的变量的名称。
- 导出: 使用关键字export,分为具名导出(普通导出),可以导出多个;默认导出,只能导出一个;
- 静态导入的代码绑定的符号是常量,不可更改
// //仅运行一次该模块,不导入任何内容 // import "模块路径" // // 常用,导入属性 a、b,放到变量a、b中。a->a, b->b // import { a, b } from "模块路径" // // 常用,导入属性 default,放入变量c中。default->c // import c from "模块 路径" // // 常用,default->c,a->a, b->b // import c, { a, b } from "模块路径" // // 常用,将模块对象放入到变量obj中 // import * as obj from "模块路径" // // 导入属性a、b,放到变量temp1、temp2 中 // import {a as temp1, b as temp2} from "模块路径" // // 导入属性default,放入变量a中,default是关键字,不能作为变量名,必须定义别名 // import {default as a} from "模块路径" // //导入属性default、b,放入变量a、b中 // import {default as a, b} from "模块路径" // // 以上均为静态导入 // import("模块路径") // 动态导入,返回一个Promise,完成时的数据为模块对象 //导出:具名导出(普通导出),可以导出多个;默认导出,只能导出一个;一个模块可以同时存在两种导出方式,最终会合并为一个「对象」导出 // export const a = 1; // 具名,常用 // export function b() {} // 具名,常用 // export const c = () => {} // 具名,常用 // const d = 2; // export { d } // 具名 // const k = 10 // export { k as temp } // 具名 // export default 3 // 默认,常用 // export default function() {} // 默认,常用 // const e = 4; // export { e as default } // 默认 // const f = 4, g = 5, h = 6 // export { f, g, h as default} // 基本 + 默认 // 以上代码将导出下面的对象 /* { a: 1, b: fn, c: fn, d: 2, temp: 10, f: 4, g: 5, default: 6 } */ // export {xx} // import {xx} from './' // export default xx // import xx from './' 复制代码
3. commonJS和ES Module的区别
-
导入时文件后缀:
- ommonJS在导入时可以省略文件后缀.js,而ES Module不可以省略
-
依赖类型
- commonJS为"动态依赖",在运行到代码块的时候才导入其他东西,导出可以写在其他代码块中
- ES Module为"静态依赖",在代码运行之前分析出依赖关系,导出时必须为顶级导出,不能放在代码块中
- ES Module中出现import('模块路径')函数时才可以动态依赖
-
运行环境
- commonJs可以直接在node上面运行,而Es Module则要么加上type="module"后在浏览器运行,要么在node运行时需要在package.json里面加上type="module"
git常用命令
- git clone 拷贝一份远程仓库,也就是下载一个项目。
- git push 上传远程代码并合并
- git add 添加文件到仓库
- git commit 将暂存区内容添加到仓库中。
- git checkout 可以进行分支转换
- git pull 下载远程代码并合并
- git remote 远程仓库操作
MVVM开发模式
1. MVVM
- 概念: MVVM 是 Model、View、ViewModel的缩写,Model 代表数据模型,数据和业务逻辑都在Model层中定义;View 代表UI视图,负责数据的展示;ViewModel负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作;
- 优点:
- 分离视图(View)和模型( Model ) , 降低代码耦合,提高视图或者逻辑的重⽤性 : ⽐如视图(View)可以独⽴于 Model变化和修改,⼀个 ViewModel 可以绑定不同的 "View" 上,当 View 变化的时候 Model 不可以不变,当 Model 变化 的时候View 也可以不变。你可以把⼀些视图逻辑放在⼀个 ViewModel ⾥⾯,让很多 view 重⽤这段视图逻辑。
- 提高可测试性 : ViewModel 的存在可以帮助开发者更好地编写测试代码。
- 自动更新 dom: 利⽤双向绑定 , 数据更新后视图自动更新 , 让开发者从繁琐的⼿动 dom 中解放。
- 缺点:
- Bug 很难被调试 : 因为使⽤双向绑定的模式,当你看到界⾯异常了,有可能是你 View 的代码有 Bug ,也可能是 Model 的代码有问题。数据绑定使得⼀个位置的Bug 被快速传递到别的位置,要定位原始出问题的地⽅就变得不那么容易 了。另外,数据绑定的声明是指令式地写在View 的模版当中的,这些内容是没办法去打断点 debug 的。
- ⼀个⼤的模块中 model 也会很⼤,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时⻓期持有,不释放内存就造 成了花费更多的内存。
- 对于⼤型的图形应⽤程序,视图状态较多, ViewModel 的构建和维护的成本都会⽐较⾼。
v-if和v-show的区别?
v-if可以拥有更多的分支,v-else等,会删除和添加元素,控制dom元素的有和没有,有效的减少树的结点和渲染量,但是导致树不稳定 而v-show没有分支,只是切换属性样式,不能改动元素,dom元素始终都在 树的渲染效率取决于(树的节点,渲染量和树的稳定性)
vue响应式
响应式原理
- 监听数据的变化,数据劫持
- 收集数据的依赖
- 当数据发生变化的时候更新渲染视图
- vue2的响应式原理 要使用的是Object.defineProperty( ) ,里面需要传入三个参数,分别是:
(源数据的对象,源数据中的需要读写的属性,相对应的对象方法(包含了get和set方法)) - vue3的响应式原理主要依靠的是ES6新增的 Proxy 以及相配合的 Reflect实现的,需要在Proxy的实例对象中传入两个参数 (源数据对象,处理对象的方法(get,set,deleteProperty…等))
- vue3的响应式相对于vue2来说简洁了很多,主要体现的地方就是我们用了Proxy的实例对象之后,不需要在单独的想vue2之中那样(使用的defineProperty)需要特意去知名监控某个对象的变化(name、age属性)。这个是很重要的一个变化。
vue双向数据绑定
vue是通过数据劫持和发布订阅者模式来实现双向数据绑定的 就是利用oberver来监听module数据的变化,通过compile来解析模板,最终通过watcher来建立oberver和module之间的通信桥梁 创建一个vue对象,分为el模板和data数据
使用Object.definePropertype来劫持data中的每个属性的getter和setter,在数据发生变化的时候发布消息给订阅者,触发相应的回调。(vue3使用proxy劫持数据)也就是observer的功能 compile 解析模板,将模板中的变量替换成数据,然后动态渲染页面, 将双向绑定的指令对应的节点添加更新函数,添加监听数据的订阅者,一旦数据有变化,就更新视图 Watcher订阅者是Observer和Compile之间通信的桥梁,他负责往dep里添加订阅者,当收到数据变化的通知时,触发compile的回调,更新视图 (vue中就是每当有这样的可能用到双向绑定的指令,就在一个Dep中增加一个订阅者)
vue-router
vue-router提供了三种)
- 1.hash:默认值,路由从浏览器地址栏中的hash部分获取路径,改变路径也是改变hash的部分,兼容性最好,不刷新页面;
- 2.history:路由从浏览器地址栏中的location.pathname部分获取路径,改变路径使用H5的history api(history.pushState(null,null,"/blog")),该模式可以让地址栏友好,看起来舒服,也需要浏览器支持history api;
- 3.abstract:路由从内存中获取路径,改变路径也只是改动内存中的值,这种模式通常应用到非浏览器环境中。
vue-router提供了全局组件RouterLink,根据模式生成超链接,渲染结果是一个a元素 对于mode:hash生成,内容 对于mode:history生成,内容,为了避免刷新页面,vue-router实际上为它添加了点击事件,并阻止了默认行为,在事件内部使用history api更改路径。
激活状态 vue-router会用当前路径匹配导航路径 精确匹配: 当前路径和导航路径完全相同,会为a元素添加类名router-link-exact-active 模糊匹配:以导航路径开头,会为a元素添加类名router-link-active 可以为RouterLink添加属性exact,匹配规则变为:必须要精确匹配才可以添加类名router-link-active 而对于文章页面,exact:false,则不需要精确匹配,可以模糊匹配为它后面添加地址,然后只有router-link-active类名
HTTP
1. 概念:
- 超文本传输协议(hypertext transfer prototal) 是客户端和服务器端互相通信时必须遵守的协议。HTTP协议是应用层协议,底层是基于TCP协议,默认是用80端口。
2. 请求方法:
- GET: 向服务器获取数据;
- POST:将实体提交到指定的资源,通常会造成服务器资源的修改;
- PUT:上传文件,更新数据;
- DELETE:删除服务器上的对象;
- HEAD:获取报文首部,与GET相比,不返回报文主体部分;
- OPTIONS:询问支持的请求方法,用来跨域请求;
- CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信;
- TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。
3. GET和POST请求区别:
- get用来获取数据,post用来提交数据
- 浏览器由于对 url 长度的限制,所以对get参数有长度限制(受限于url长度,具体的数值取决于浏览器和服务器的限制,最长2048字节),而post无限制。
- get请求的数据会附加在url之后 ,用 " ? "分割url和传输数据,多个参数用 "&"连接,而post请求会把请求的数据放在http请求体中。
- get是明文传输,post是放在请求体中,但是开发者可以通过抓包工具看到,也相当于是明文的。
- 浏览器一般会对 get 请求缓存,但很少对 post 请求缓存。
- 应用场景: 一般 get 请求用于对服务器资源不会产生影响的场景,比如说请求一个网页的资源;post 请求一般用于对服务器资源会产生影响的情景,比如注册用户这一类的操作。
- 发送的报文格式: get 请求的报文中实体部分为空,post 请求的报文中实体部分一般为向服务器发送的数据。
- 安全性: get 请求可以将请求的参数放入 url 中向服务器发送,这样的做法相对于 post 请求来说是不太安全的,因为请求的 url 会被保留在历史记录中。
4. post和put请求的区别
- put请求是向服务器端发送数据,从而修改数据的内容,但是不会增加数据的种类等。(更新数据)
- post请求是向服务器端发送数据,该请求会改变数据的种类等资源,它会创建新的内容。(创建数据)
5. 常见的HTTP请求头和响应头
- HTTP Request Header 常见的请求头:
- Accept:浏览器能够处理的内容类型
- Accept-Charset:浏览器能够显示的字符集
- Accept-Encoding:浏览器能够处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Connection:浏览器与服务器之间连接的类型
- Cookie:当前页面设置的任何Cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的页面的URL
- User-Agent:浏览器的用户代理字符串
- HTTP Responses Header 常见的响应头:
- Date:表示消息发送的时间,时间的描述格式由rfc822定义
- server:服务器名称
- Connection:浏览器与服务器之间连接的类型
- Cache-Control:控制HTTP缓存
- content-type:表示后面的文档属于什么MIME类型
- 常见的 Content-Type 属性值有以下四种:
- pplication/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。
- multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
- application/json:服务器消息主体是序列化后的 JSON 字符串。
- text/xml:该种方式主要用来提交 XML 格式的数据。
6. HTTP 1.0----HTTP 1.1----HTTP 2.0
- HTTP 1.0 与 HTTP 1.1主要区别
- 连接方面: HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP 1.1默认支持长连接,这样减少创建连接的开销,提高了效率。(HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响,因此最好能维持一个长连接,可以用个长连接来发多个请求)。
- 资源请求方面: 在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 缓存方面,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- http1.1 中 新增了 host 字段,用来指定服务器的域名。http1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了 host 字段,这样就可以将请求发往到同一台服务器上的不同网站。
- http1.1 相对于 http1.0 还新增了很多请求方法,如 PUT、HEAD、OPTIONS 等。
7. HTTP 1.0 与 HTTP 1.1主要区别
- 二进制协议: HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
- 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。
- 数据流: HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
8. HTTP3.0
- 基于UDP协议实现了类似于TCP的多路复用数据流、传输可靠性等功能,这套功能被称为QUIC协议,流量控制、传输可靠性功能,集成TLS加密功能,多路复用。
- 状态码:
1XX: 服务器端已收到请求
2XX: 成功 200ok
3XX: 重定向/缓存 301永久重定向 302临时重定向 304资源未更改
4XX: 客户端错误 403请求页面禁止访问 404not found资源不存在,比如输入错误的url
5XX: 服务器端错误 500服务器代码问题
9. keep-alive
- 出现原因: HTTP1.0 中默认是在每次请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接,这就是短连接。当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接,这就是长连接。
- 使用方法:
- HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送
Connection: keep-alive字段。若想断开keep-alive连接,需发送Connection:close字段; - HTTP1.1规定了默认保持长连接,数据传输完成了保持TCP连接不断开,等待在同域名下继续用这个通道传输数据。如果需要关闭,需要客户端发送
Connection:close首部字段。
- HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送
- Keep-Alive的建立过程:
- 客户端向服务器在发送请求报文同时在首部添加发送Connection字段
- 服务器收到请求并处理 Connection字段
- 服务器回送Connection:Keep-Alive字段给客户端
- 客户端接收到Connection字段
- Keep-Alive连接建立成功
- 服务端自动断开过程(也就是没有keep-alive):
- 客户端向服务器只是发送内容报文(不包含Connection字段)
- 服务器收到请求并处理
- 服务器返回客户端请求的资源并关闭连接
- 客户端接收资源,发现没有Connection字段,断开连接
- 客户端请求断开连接过程:
- 客户端向服务器发送Connection:close字段
- 服务器收到请求并处理connection字段
- 服务器回送响应资源并断开连接
- 客户端接收资源并断开连接
- 开启Keep-Alive的优点:
- 较少的CPU和内存的使⽤(由于同时打开的连接的减少了);
- 允许请求和应答的HTTP管线化;
- 降低拥塞控制 (TCP连接减少了);
- 减少了后续请求的延迟(⽆需再进⾏握⼿);
- 报告错误⽆需关闭TCP连;
- 开启Keep-Alive的缺点:
- 长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。
HTTPS
1. 概念:
- 是超文本传输安全协议,一种通过计算机网络进行安全通信的传输协议,HTTPS经由HTTP进行通信,利用SSL/TLS来加密数据包。(安全层:对发起的HTTP请求的数据进行加密操作 和 对接收到的HTTP的内容进行解密操作。)
2. 主要目的:
- 是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
3. 特点:
- 可以进行加密传输、身份认证,通信更加安全,防止数据在传输过程中被窃取、修改,确保数据安全性;可以认证用户和服务器,确保数据发送到正确的客户端和服务器;需要做服务器和客户端双方的加密和解密处理,耗费更多服务器资源,过程复杂;SSL证书是收费的,功能越强大的证书费用越高。
4. 和HTTP的区别?
- HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以避免此类问题发生。HTTP通常运行在TCP之上,HTTPS存在于HTTP和TCP之间,HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,https需要申请CA证书,付费;http默认端口号80,https默认端口号443;
5. TLS/SSL的工作原理
- 概念: 安全传输层协议(Transport Layer Security), 是介于TCP和HTTP之间的一层安全协议,不影响原有的TCP协议和HTTP协议,所以使用HTTPS基本上不需要对HTTP页面进行太多的改造。
- TLS/SSL实现: TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash (验证信息的完整性)、对称加密算法(采用协商的秘钥对数据加密)、非对称加密算法 (实现身份认证和秘钥协商)。\
6. HTTPS加密过程:
-
分为证书验证和数据传输阶段
证书验证阶段--->非对称加密数据内容阶段--->对称加密。具体过程- 客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。
- 服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。
- 客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服 务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。
- 服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。
- 客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。
7. HTTPS是如何保证安全的?
- 结合两种加密⽅式,将对称加密的密钥使⽤⾮对称加密的公钥进⾏加密,然后发送出去,接收⽅使⽤私钥进⾏解密得到对称加密的密钥,然后双⽅可以使⽤对称加密来进⾏沟通。
- 此时⼜带来⼀个问题,中间⼈问题: 如果此时在客户端和服务器之间存在⼀个中间⼈,这个中间⼈只需要把原本双⽅通信互发的公钥,换成⾃⼰的公钥,这样中间⼈就可以轻松解密通信双⽅所发送的所有数据。
- 所以这个时候需要⼀个安全的第三⽅颁发证书(CA),证明身份的身份,防⽌被中间⼈攻击。 证书中包括:签发者、证书⽤途、使⽤者公钥、使⽤者私钥、使⽤者的HASH算法、证书到期时间等。
- 但是问题来了,如果中间⼈篡改了证书,那么身份证明是不是就⽆效了?这个证明就⽩买了,这个时候需要⼀个新的技术,数字签名。
- 数字签名就是⽤CA⾃带的HASH算法对证书的内容进⾏HASH得到⼀个摘要,再⽤CA的私钥加密,最终组成数字签名。当别⼈把他的证书发过来的时候,我再⽤同样的Hash算法,再次⽣成消息摘要,然后⽤CA的公钥对数字签名解密,得到CA创建的消息摘要,两者⼀⽐,就知道中间有没有被⼈篡改了。这个时候就能最⼤程度保证通信的安全了。
对称加密、非对称加密
1. 对称加密:
- 原理: 双方使用同一个秘钥对数据进行加密和解密。因为秘钥是会通过网络传输的,那么需要保证秘钥传输的安全性,一旦秘钥被其他人获取到,那么整个加密过程就毫无作用了。(常见的对称加密算法有AES-CBC、DES、3DES、AES-GCM等)。。
- 特点: 算法简单,加密解密容易,效率高,执行快,相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译。
- 应用场景: 可以用来传递一些隐秘的信息,因为只有双方有密钥,比如客户端和服务端。
2. 非对称加密:
- 原理: 拥有两个秘钥,一个是公钥,一个是私钥。公钥是公开的,私钥是保密的。用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。(可以将公钥公布出去,任何想和我们通信的客户,都可以使用我们提供的公钥对数据进行加密,这样我们就可以使用私钥进行解密,这样就能保证数据的安全了)。
- 特点: 安全,即使密文被拦截、公钥被获取,但是无法获取到私钥,也就无法破译密文。作为接收方,务必要保管好自己的密钥。缺点 加密算法及其复杂,安全性依赖算法与密钥,而且加密和解密效率很低,加密的过程很慢,因此如果每次通信都使用非对称加密的方式的话,反而会造成等待时间过长的问题。
- 应用场景: 签名(服务端加签、客户端解签验证)、秘钥交换,证书等场景。
3. 数字证书
- 出现原因: 因为没有办法确定得到的公钥就一定是安全的公钥。可能存在一个中间人,截取了对方发给我们的公钥,然后将他自己的公钥发送给我们,当我们使用他的公钥加密后发送的信息,就可以被他用自己的私钥解密。然后他伪装成我们以同样的方法向对方发送信息,这样我们的信息就被窃取了,然而自己还不知道。为了解决这样的问题,可以使用数字证书。
- 概念: 使用 Hash 算法来对公钥和其他信息进行加密,生成一个信息摘要,然后让有公信力的认证中心(简称 CA )用它的私钥对消息摘要加密,形成签名。最后将原始的信息和签名合在一起,称为数字证书。
TCP和UDP
1. TCP、UDP的概念以及特点
-
TCP 和 UDP都是传输层协议,他们都属于TCP/IP协议族;
-
UDP也叫作 用户数据报协议 ,在网络中主要用来处理数据包,是一种无连接协议,在OSI模型中,它在传输层。
- UDP是面向无连接的,也就是在发送数据前不需要进行三次握手建立连接,也不会对数据报文进行任何拆分和拼接操作,所以在报文发送后,它不知道报文有没有安全、完整的到达。
- UDP有单播,多播,广播的功能,它的连接个数支持一对一,一对多,多对一和多对多交互通信。
- 它的传输方式是面向报文,UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界,在添加首部后就向下交付IP层,因此,应用程序必须选择合适大小的报文。
- 不可靠性: 一方面体现在无连接上,另一方面它没有拥塞控制和流量控制,一直会以恒定的速度发送数据,跟网络环境没有关系。
- 头部开销小,只有8字节,相比 TCP 的少20多个字节,在传输数据报文时是很高效的。
- 一般适用于实时应用,像视频会议、直播这些时实通讯,速度要求高的。
-
TCP 全称是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- TCP的面向连接体现在,发送数据之前必须在两端建立连接,也就是三次握手,为数据的可靠传输打下了基础。
- 仅支持单播传输 每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
- 面向字节流 它UDP一样那样,一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。
- 可靠传输 会通过用TCP的段编号和确认号来判断有没有出现丢包、误码这种情况, 能保证数据的顺序和正确性。具体的话,会给每个包一个序号,保证了接收端按序接收包;同时接收端实体会对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
- 使用流量控制 和 拥塞控制,当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
- 提供全双工通信 允许通信双方的应用程序在任何时候都能发送数据。
- 一般适用于要求可靠传输的应用,像文件传输这种对准确性要求较高,效率要求相对低的。
2. 两者的区别
3. UDP为什么不可靠?
- 在传输数据之前不需要先建立连接,在接收到UDP报文后,不需要确认,提供不可靠交付,也不重传。
- 不保证交付的顺序,不设置包序号,不重排。
- 不进行拥塞控制和流量控制,发送数据跟网络环境没有关系。
- (UDP只有一个socket接受缓冲区,没有socket发送缓冲区,即只要有数据就发,不管对方是否可以正确接受。 而在对方的socket接受缓冲区满了之后,新来的数据报无法进入到socket接受缓冲区,此数据报就会被丢弃,UDP是没有流量控制的,所以UDP的数据传输是不可靠的)
4. TCP为什么可靠?它的重传机制是什么?
- 使用序列号和确认应答:接收方在接收到消息后会返回给发送方一个应答确认信号,也就是ACK。
- 重发超时:使用了ACK使发送方知道数据有没有送达,如果消息发送失败了,TCP会根据往返时间与偏差计算重发超时时间,考虑偏差主要是网络环境存在波动,数据重发之后如果仍无法收到应答,则再次发送,此时,等待确认应答的时间将会以2、4、8倍的指数延长,数据也不会无限重发,当达到一定次数后,则自动判断对方异常,强制关闭连接。
- 三次握手、四次挥手: 在正式通信之前会和服务器请求建立连接,结束时也会请求断开连接。
- 拥塞控制和流量控制(流量控制:TCP实现了发送方可以根据接收方接收能力实现动态控制发送数据量的机制,这里控制的数据量实际也是窗口大小)
- 重传机制: 由于TCP的下层网络(网络层)可能出现丢失、重复或失序的情况,TCP协议提供可靠数据传输服务。为保证数据传输的正确性,TCP会重传那些它认为已经丢失(包括报文中的比特错误)的包。TCP使用两套独立的机制来完成重传,一是基于时间,二是基于确认信息。 TCP在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。
作者:jiajiashang
链接:juejin.cn/post/713989…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
同源策略
1. 同源策略
-
概念: protocol(协议)、domain(域名)、port(端口)三者必须一致。
-
限制方面:
- 当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。
- 当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。
- 当前域下 ajax 无法发送跨域请求。
-
目的 主要是为了保证用户的信息安全,它只是对 js 脚本的一种限制,并不是对浏览器的限制,对于一般的 img、或者script 脚本请求都不会有跨域的限制,这是因为这些操作都不会通过响应结果来进行可能出现安全问题的操作。
浏览器的事件机制
1. 事件:
-
事件的概念: 是用户操作页面时发生的交互动作,比如click/move等,事件除了用户触发的动作外,还可以是文档加载、窗口滚动和大小调整。事件被封装为一个event对象,包含了事件的属性和方法。
-
事件流: 事件的流向,先捕获,再到事件源,最后再冒泡,在DOM2级事件模型中,事件流分为三个阶段:事件捕获、事件处理、事件冒泡。
-
事件模型:
- DOM0级事件模型: 可以在网页中直接定义监听函数,也可以通过js来指定监听函数,直接在DOM对象上注册事件。
- IE事件模型: 该事件模型共有两个过程:事件处理阶段和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
- DOM2级事件模型: 一共三个过程:事件捕获阶段:事件从document一直向下传播到目标元素,依次检查经过的结点是否绑定了事件监听函数,如果绑定则执行。后两个阶段与IE事件模型相同。
2. 事件捕获:
- 概念: 在捕获的过程中,最外层(根)元素的事件先被触发,然后依次向内执行,直到触发最里面的元素(事件源),自顶向下的过程。
3. 事件冒泡:
- 概念: 在冒泡过程中,自子元素冒泡向父元素。(自底向上),当子元素(事件源)事件触发,事件会沿着包含关系,依次往上级传递,每一级都可以感知到事件,直到触发根元素(根源)。
- 阻止冒泡:
- 普通浏览器使用:event.stopPropagation(),不让事件向documen上蔓延。
- IE浏览器独有,设置:event.cancelBubble = true;
- 也可以封装一个取消冒泡的函数stopBubble(event),主要是将以上两种方法合并兼容,对于任何浏览器都调用函数来使用。
4. 事件代理(事件委托)
- 概念: 事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件委托(事件代理)。
- 事件委托的优点:
- 可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件。
- 可以实现当新增子对象时无需再次对其绑定(动态绑定事件)。
- 使用场景: 如果我们有⼀个列表,列表之中有⼤量的列表项,我们需要在点击列表项的时候响应⼀个事件,如果给每个列表项⼀⼀都绑定⼀个函数,那对于内存消耗是⾮常⼤的,这时候就可以事件委托,把点击事件绑定在⽗级元素 ul 上⾯,然后执⾏事件的时候再去匹配⽬标元素。
5. 事件循环
- JS是一个单线程的脚本语言,一般情况下代码是同步执行的,所以js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个异步事件放到任务队列里面,继续执行执行栈中的其他任务。任务队列里面存放两种任务,又分为宏任务和微任务。
- 宏任务: setTimeout,setInterval
- 微任务: Promise.then那些,process.nextTick
- 当前执行栈执行完毕时,主线程会查看微任务队列有没有事件等待执行,如果有就将其压入执行栈中执行,如果没有,就查看宏任务队列有无事件。如此反复循环。
- 执行的顺序是:主线程->微任务队列 ->宏任务队列
- 任务队列: 任务队列是一个先进先出的队列,它里面存放着各种任务回调。
- 事件轮询: 事件轮询是指主线程重复从任务队列中取任务、执行任务的过程。
6. 同步和异步的区别
- 同步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,那么这个进程会一直等待下去,直到消息返回为止再继续向下执行。
- 异步指的是当一个进程在执行某个请求时,如果这个请求需要等待一段时间才能返回,这个时候进程会继续往下执行,不会阻塞等待消息的返回,当消息返回时系统再通知进程进行处理。
Ajax
原理
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
- 作用: ajax是一个可以不使页面重新加载刷新的情况下,可以与服务器进行交互,并更新网页部分区域的技术
- 原理: 通过XMLHttpRequest对象来向服务器发送请求,然后通过js来操作DOM实现页面的更新就是在客户端和服务器端加了一个中间层,使得用户操作和对服务器的请求异步。
- 手写(promise实现)
function ajax(url, methods) { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest() // 初始化 xhr.open(methods, url, true) // 发送 xhr.send() // 处理响应结果 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response) } else { reject(xhr.status) } } } }) } - xhr.readystate:
- 0 (未初始化)还没调用send方法
- 1 (载入)调用了send方法,正在发送请求
- 2 (载入完成)已经接受到相应
- 3 解析响应结果
- 4 解析完成
- xhr.status(状态码)
- 2XX:表示成功处理请求
- 3XX:需要重定向,301(永久重定向) 302(临时重定向)304()
- 4XX:客户端请求错误,404(请求地址错误) 403(没有权限)
- 5XX:服务器端有问题
跨域
产生原因:
- 由于浏览器的同源策略限制,浏览器会拒绝跨域的请求。
解决方式:
1. CORS
- 跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器,让运行在一个 origin (domain)上的Web应用被准许访问来自不同源服务器上的指定的资源。 当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域HTTP 请求。
- CORS需要浏览器和服务器同时支持, 整个CORS过程都是浏览器完成的,无需用户参与。因此实现CORS的关键就是服务器,只要服务器实现了CORS请求,就可以跨源通信了。
- 浏览器将CORS分为简单请求和非简单请求:
-
简单请求 不会触发CORS预检请求,在简单请求中,在服务器内,至少需要设置字段:
Access-Control-Allow-Origin。若该请求满足以下两个条件,就可以看作是简单请求:- 请求方法是以下三种方法之一
- HEAD
- GET
- POST
- HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain 若不满足以上条件,就属于非简单请求了。
- 简单请求过程:
对于简单请求,浏览器会直接发出CORS请求,它会在请求的头信息中增加一个Orign字段,该字段用来说明本次请求来自哪个源(协议+端口+域名),服务器会根据这个值来决定是否同意这次请求。如果Orign指定的域名在许可范围之内,服务器返回的响应就会多出以下信息头:
如果Orign指定的域名不在许可范围之内,服务器会返回一个正常的HTTP回应,浏览器发现没有上面的Access-Control-Allow-Origin头部信息,就知道出错了。这个错误无法通过状态码识别,因为返回的状态码可能是200。Access-Control-Allow-Origin: http://api.bob.com // 和Orign一直 Access-Control-Allow-Credentials: true // 表示是否允许发送Cookie Access-Control-Expose-Headers: FooBar // 指定返回其他字段的值 Content-Type: text/html; charset=utf-8 // 表示文档类型
- 请求方法是以下三种方法之一
-
非简单请求过程
- 非简单请求是对服务器有特殊要求的请求,比如请求方法为DELETE或者PUT等。非简单请求的CORS请求会在正式通信之前进行一次HTTP查询请求,称为预检请求。
- 浏览器会询问服务器,当前所在的网页是否在服务器允许访问的范围内,以及可以使用哪些HTTP请求方式和头信息字段,只有得到肯定的回复,才会进行正式的HTTP请求,否则就会报错。 预检请求使用的请求方法是OPTIONS,表示这个请求是来询问的。他的头信息中的关键字段是Orign,表示请求来自哪个源。除此之外,头信息中还包括两个字段:
- Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。
- Access-Control-Request-Headers: 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进行判断,如果返回的头信息在中有Access-Control-Allow-Origin这个字段就是允许跨域请求,如果没有,就是不同意这个预检请求,就会报错。
-
服务器回应的CORS的字段如下:
Access-Control-Allow-Origin: http://api.bob.com // 允许跨域的源地址
Access-Control-Allow-Methods: GET, POST, PUT // 服务器支持的所有跨域请求的方法
Access-Control-Allow-Headers: X-Custom-Header // 服务器支持的所有头信息字段
Access-Control-Allow-Credentials: true // 表示是否允许发送Cookie
Access-Control-Max-Age: 1728000 // 用来指定本次预检请求的有效期,单位为秒
复制代码
只要服务器通过了预检请求,在以后每次的CORS请求都会自带一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。 在非简单请求中,至少需要设置以下字段:
'Access-Control-Allow-Origin'
'Access-Control-Allow-Methods'
'Access-Control-Allow-Headers'
- 减少OPTIONS请求次数: OPTIONS请求次数过多就会损耗页面加载的性能,降低用户体验度。所以尽量要减少OPTIONS请求次数,可以后端在请求的返回头部添加:Access-Control-Max-Age:number。它表示预检请求的返回结果可以被缓存多久,单位是秒。该字段只对完全一样的URL的缓存设置生效,所以设置了缓存时间,在这个时间范围内,再次发送请求就不需要进行预检请求了。
- CORS中Cookie相关问题: 在CORS请求中,如果想要传递Cookie,就要满足以下三个条件:
- 在请求中设置
withCredentials默认情况下在跨域请求,浏览器是不带 cookie 的。但是我们可以通过设置 withCredentials 来进行传递 cookie.
// 原生 xml 的设置方式
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
// axios 设置方式
axios.defaults.withCredentials = true;
复制代码
- Access-Control-Allow-Credentials 设置为 true
- Access-Control-Allow-Origin 设置为非
*
2. JSONP
- 原理 就是利用
<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。 - 原生JS实现:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
复制代码
服务端返回如下(返回时即执行全局函数):
handleCallback({"success": true, "user": "admin"})
复制代码
- Vue axios实现:
this.$http = axios;
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
复制代码
后端node.js代码:
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var params = querystring.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回设置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
复制代码
- JSONP的缺点:
- 具有局限性, 仅支持get方法
- 不安全,可能会遭受XSS攻击
3. postMessage 跨域
- postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递 用法:postMessage(data,origin)方法接受两个参数:
- data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
- origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
1)a.html:(domain1.com/a.html)
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'aym'
};
// 向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
};
// 接受domain2返回数据
window.addEventListener('message', function(e) {
alert('data from domain2 ---> ' + e.data);
}, false);
</script>
复制代码
2)b.html:(domain2.com/b.html)
<script>
// 接收domain1的数据
window.addEventListener('message', function(e) {
alert('data from domain1 ---> ' + e.data);
var data = JSON.parse(e.data);
if (data) {
data.number = 16;
// 处理后再发回domain1
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
}
}, false);
</script>
复制代码
4. nginx代理跨域
- nginx代理跨域,实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。
- 1)nginx配置解决iconfont跨域 浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。
location / {
add_header Access-Control-Allow-Origin *;
}
复制代码
- 2)nginx反向代理接口跨域 跨域问题:同源策略仅是针对浏览器的安全策略。服务器端调用HTTP接口只是使用HTTP协议,不需要同源策略,也就不存在跨域问题。 实现思路:通过Nginx配置一个代理服务器域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。
nginx具体配置:
#proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
5. nodejs 中间件代理跨域
- node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
1)非vue框架的跨域 使用node + express + http-proxy-middleware搭建一个proxy服务器。
- 前端代码:
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问http-proxy-middleware代理服务器
xhr.open('get', 'http://www.domain1.com:3000/login?user=admin', true);
xhr.send();
复制代码
- 中间件服务器代码:
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/', proxy({
// 代理跨域目标接口
target: 'http://www.domain2.com:8080',
changeOrigin: true,
// 修改响应头信息,实现跨域并允许带cookie
onProxyRes: function(proxyRes, req, res) {
res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
res.header('Access-Control-Allow-Credentials', 'true');
},
// 修改响应信息中的cookie域名
cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
}));
app.listen(3000);
console.log('Proxy server is listen at port 3000...');
复制代码
2)vue框架的跨域
node + vue + webpack + webpack-dev-server搭建的项目,跨域请求接口,直接修改webpack.config.js配置。开发环境下,vue渲染服务和接口代理服务都是webpack-dev-server同一个,所以页面与代理接口之间不再跨域。
webpack.config.js部分配置:
module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.domain2.com:8080', // 代理跨域目标接口
changeOrigin: true,
secure: false, // 当代理某些https服务报错时用
cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
}],
noInfo: true
}
}
6. WebSocket协议跨域
- WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
1)前端代码:
<div>user input:<input type="text"></div>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');
// 连接成功处理
socket.on('connect', function() {
// 监听服务端消息
socket.on('message', function(msg) {
console.log('data from server: ---> ' + msg);
});
// 监听服务端关闭
socket.on('disconnect', function() {
console.log('Server socket has closed.');
});
});
document.getElementsByTagName('input')[0].onblur = function() {
socket.send(this.value);
};
</script>
复制代码
2)Nodejs socket后台:
var http = require('http');
var socket = require('socket.io');
// 启http服务
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
// 监听socket连接
socket.listen(server).on('connection', function(client) {
// 接收信息
client.on('message', function(msg) {
client.send('hello:' + msg);
console.log('data from client: ---> ' + msg);
});
// 断开处理
client.on('disconnect', function() {
console.log('Client socket has closed.');
});
});
7. document.domain + iframe跨域
8. location.hash + iframe跨域
9. window.name + iframe跨域
Axios网络请求
概念
- Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
特性
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
使用方式
- axios(config)
- axios.method(url, data , config)
session cookie localstorage
-
概念:
cookie:是最早被提出来的本地存储方式,主要在HTML5标准前使用,在此之前,服务端是无法判断网络中的两个请求是否是同一用户发起的,为解决这个问题,Cookie就出现了。cookie存放数据大小一般为4K左右,它的特点是兼容性比较好。每次请求都会向客户端发送,关闭页面不会消失 有可能被坏人复制窃取cookie去登录(xss注入攻击来攻击cookie)(cookie是一种纯文本文件,每次发起HTTP请求都会携带Cookie,cookie字段一般有Domain(域)、Path(路径)、Secure(安全)(是否只有在HTTP使用SSL连接时才发送这个Cookie)、expires(过期)、name(名字)、value(值)这些配置选项。cookie一旦创建成功,名称就无法修改,也无法跨域名,如果需要域名之间跨域共享Cookie,有两种方法:使用Nginx反向代理;在一个站点登陆之后,往其他网站写Cookie,服务端的Session存储到一个节点,Cookie存储sessionId) 使用场景: 最常见的使用场景就是cookie和session结合使用,将sessionId存储到cookie中,每次发请求都会携带这个sessionId,这样服务端就知道是谁发起的请求,从而响应相应的信息;可以用来统计页面的点击次数。localStorage: 是HTML5新引入的特性,localStorage的大小一般为5MB,可以储存更多的信息,localStorage是持久储存,并不会随着页面的关闭而消失,除非主动清理,不然会永久储存在本地,它不像Cookie那样每次HTTP请求都会被携带。但也存在浏览器兼容问题,IE8以下版本的浏览器不支持,如果浏览器设置为隐私模式,那我们将无法读取到LocalStorage,同时,它也受到同源策略的限制。 (常用的API: 1. 保存数据到localStorage(localStorage.setItem('key', 'value')); 2. 从localStorage获取数据(let data = localStorage.getItem('key'));3. 从 localStorage 删除保存的数据(localStorage.removeItem('key'));4. 从localStorage删除所有保存的数据(localStorage.clear());5. 获取某个索引的Key(localStorage.key(index));) 使用场景:有些网站有换肤的功能,这时候就可以将换肤的信息存储在本地的LocalStorage中,当需要换肤的时候,直接操作LocalStorage即可; 在网站中的用户浏览信息也会存储在LocalStorage中,还有网站的一些不常变动的个人信息等也可以存储在本地的LocalStorage中。sessionStorage:SessionStorage和LocalStorage都是在HTML5才提出来的存储方案,是会话级别的储存⽅式,SessionStorage 主要用于临时保存同一窗口(或标签页)的数据,刷新页面时不会删除,关闭窗口或标签页之后将会删除这些数据。存放数据大小一般为5MB,存储在服务器端,也有同源策略的限制,只有在同一浏览器的同一窗口下才能够共享。 (常用的API: 与localStorage类似,改下名字就行) 使用场景:由于SessionStorage具有时效性,所以可以用来存储一些网站的游客登录的信息,还有临时的浏览记录的信息。当关闭网站之后,这些信息也就随之消除了。IndexedDB: indexedDB 是一个基于js的面向对象的数据库,⽤键值对进⾏储存,可以进⾏快速读取操作,适合web场景,同时,它也受到同源限制,网页只能访问自身域名下的数据库,而不能访问跨域的数据库,它的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。Web SQL: 2010年被W3C废弃的本地数据库数据存储⽅案,但是主流浏览器(⽕狐除外)都已经有了相关的实现,web sql类似于SQLite,是真正意义上的关系型数据库,⽤sql进⾏操作,当我们⽤JavaScript时要进⾏转换,较为繁琐,因为 Web SQL database 本质上是一个关系型数据库,后端可能熟悉,但是前端就有很多不熟悉了,虽然SQL的简单操作不难,但是也得需要学习。SQL熟悉后,真实操作中还得把你要存储的东西,比如对象,转成SQL语句,也挺麻烦的。
-
区别比较
- 相同:在本地(浏览器端)存储数据,
cookie已经不建议用于存储,如果没有大量数据存储需求的话,可以使用localStorage和sessionStorage。对于不怎么改变的数据尽量使用localStorage存储,否则可以用sessionStorage存储,sessionStorage和localStorage都是html5后才出现的,所以用法以及场景都差不多。 - 不同: localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。 sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。 localStorage是永久存储,除非手动删除。 sessionStorage当会话结束(当前页面关闭的时候,自动销毁) cookie的数据会在每一次发送http请求的时候,同时发送给服务器而localStorage、sessionStorage不会。
- 相同:在本地(浏览器端)存储数据,
2. token存在哪?
-
Token定义: 是访问资源对凭证,一般是用户通过用户名和密码登录成功之后,服务器将登录凭证做数字签名,加密之后得到的字符串作为token,它在用户登录成功之后会返回给客户端。 -
token: 的基本使用 && 身份验证流程: 使用基于token的身份验证方法,在服务端不需要存储用户的登录记录,客户端使用用户名跟密码请求登录,服务端收到请求,验证用户名与密码,验证成功后,服务端会签发一个token,再把这个token发送给客户端,客户端收到token以后可以把它存储起来,比如放在Cookie里或者Local Storage里,客户端每次向服务端请求资源的时候需要带着服务端签发的Token,服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据。 -
Token存储位置
- 存储在localStorage中,每次调用接口的时候都把它当成一个字段传给后台。
- 存储在cookie中,让它自动发送,不过缺点就是不能跨域。
- 存储在localStorage中,每次调用接口的时候放在HTTP请求头的Authorization字段里面。
-
为什么要使用token:
- token完全有应用管理,它可以避开同源策略。
- token可以避免CSRF攻击。
- token可以是无状态的,可以在多个服务间共享。
-
token的作用:
- 防止表单重复提交。
- 身份验证,识别用户权限等。
jwt
- 原理: JWT就是通过可逆加密算法,生成一串包含用户、过期时间等关键信息的Token,每次请求服务器拿到这个Token解密出来就能得到用户信息,从而判断用户状态。
- 过程:
- 客户端登录成功后(必须是在登陆成功才行,与session一样的前提条件) ,服务器会根据用户名和签名以及其他信息加密生成唯一的token串,用来区分他们,不需要存入服务端的缓存中,但会把这个token返回给相应的主机,
- 主机收到token后会存入cookie或者localStorage中,以后主机的每一次发送其他类型的请求的操作都会携带这个token,
- 服务器会将客户端发来的这个token和服务端从数据库查询出来的并且重新计算得到的用户信息进行对比,如果匹配,则认证成功,如果用户请求的资源需要相应的权限,则校验token中的payload中存储的权限等相关信息,如果有权限则返回给对应主机所需要的资源(即做到了权限鉴权),否则拒绝