目录
前言
业务篇
1.大文件上传如何实现断点续传和秒传?
机制的本质就是:"将大文件分片,发之前先对Hash值",下面是具体的4步:
- 算Hash:前端利用sparkmd5读取文件,生成唯一的hash值
- 秒传:上传前,把hash发给后端,检测后端是否存在改文件,如果存在直接上传成功
- 分片上传:利用File.slice()将文件切片,给文件标上序号,并发传给后端,全部传完后,给后端发一个合并指令
- 断点续传:如果中途断网了,用户再次点击上传,前端把hash发给后端,后端返回已接受的列表序号,前端直接把这些切片过滤掉,只上传剩下的切片
2.单点登录(SSO)
单点登录的任务就是解决Cookie无法跨域的问题 ,SSO会设立一个独立的"认证中心"用来管理Cookie认证,核心流程分为下面四步:
- 强制拦截:用户访问子系统A,发现没有登录,被重定向到SSO认证中心
- 全局登录:用户在SSO页面输入账号密码,登陆成功后,SSO会在自己域名创建一个全局Cookie,同时给前端一个临时令牌(Ticket)
- 局部登录:前端带着Ticket重定向到子系统A,子系统A的后端拿着Ticket去SSO验证真伪,如果是真的,子系统A就在自己域名创建局部Cookie,A系统登录完成
- 无缝漫游:用户接着访问子系统B,子系统B没有登录,又被重定向到SSO,但是此时SSO存在你的全局Cookie,所以会再生成一个Ticket,前端再带着这个Ticket去子系统B,子系统B会再次验证这个Ticket,如果成功,子系统B在自己域名创建局部Cookie,B系统登录完成
3.跨域
浏览器遵循的绝对铁律:"同源策略 ",只要协议 、域名 、端口有一个不一样,浏览器就会把服务器返回的数据拦截。
- 协议不同:前端是https的网页,但是向http接口发送请求
- 域名:www.baidu.com的网页向www.aidu.com发送请求
- 端口:localhost:5000的网页向localhost:6000发送请求
为了解决跨域,有下面几个常见的方式:
- CORS(跨域资源共享):后端在access-control-allow-origin里添加域名允许放行
- Proxy / Nginx(服务器代理):前端把请求发给代理,代理再把请求转发给后端
4.请求头里有什么字段
请求头是前端在发送请求时,告诉服务器这个请求的元数据,一般包含四大核心,我们按照规律解释::"身份认证 "、"内容协商 "、"路由 "、"缓存策略"
身份认证有两个:
- Authorization:Token
- Cookie
内容协商有三个:
- Content-Type:告诉后端发送的数据是什么格式(application/json还是multipart/form-data)
- Accept:希望收到什么格式的数据
- Accept-Encoding:支持哪种压缩算法
路由有三个:
- Origin(核心):记录当前请求来源的协议、域名和端口
- Referer:从哪个网址进入的
- User-Agent:操作系统、浏览器版本
缓存策略有两个:
- Cache-Control:控制强缓存
- If-None-Match:协商缓存的暗号
5.CORS(跨域资源共享)
CORS工作的原理如下:
- 浏览器把请求发给后端,在请求头里的Origin填入当前的域名
- 后端发现Origin里的域名有记录,于是在响应头里加一句Access-Control-Allow-Origin:域名
- 浏览器拿到响应头,核对了一下Allow-Origin字段,发现吻合,就把数据返回给前端的Axios
代码手写篇
1.手写文件分片
javascript
function createFileChunks(file, chunkSize = 5 * 1024 * 1024) {
const chunks = [];
const currentFileSize = 0;
while (currentFileSize < file.size) {
const chunk = File.slice(currentFileSize, currentFileSize + chunkSize);
chunks.push(chunk);
currentFileSize += chunkSize;
}
return chunks;
}
2.手写promise.any
javascript
function myPromiseAny(promises) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject('请传入一个数组');
}
let count = 0;
promises.forEach((promise) => {
Promise.resolve(promise).then((value) => {
resolve(value);
}).catch(err => {
count++;
if (count === promises.length) {
reject('所有promise都失败了');
}
})
})
})
}
myPromiseAny(Promise.reject('失败了'))
myPromiseAny([Promise.reject('失败了'), Promise.reject('又失败了'), Promise.resolve('成功了')]).then(value => {
console.log(value);
}).catch(err => {
console.log(err);
})
结果:
