1、微信扫码登陆
我上一个项目是 electron 做的后台管理系统,其中就有这个微信扫码登陆功能,这个功能需要先绑定微信账号 然后才能使用这个微信扫码登陆
这个绑定过程是:
首先,在用户管理页面选择一个用户,点击绑定按钮,此时会发送消息通知主进程,并且携带参数 token
主进程收到消息就会创建一个新的窗口,新窗口加载了一个微信登陆授权的页面,这个页面url是后端给的, 页面上有一个二维码,用户用微信扫一下这个二维码之后,会弹出是否确实授权的界面
然后前端在主进程这边监听窗口url的变化,如果用户手动点击了确认按钮,窗口 url 就会发生变化, 触发监听的回调函数,会给后端发送一个绑定请求,参数是 token 和一些绑定信息,然后关闭这个页面
后端收到绑定请求后,就处理这个绑定过程,然后会返回一个 微信授权code码 给前端
前端主进程这边收到 code 码后把这个 code 码传送给渲染进程,渲染进程拿到之后就弹出 微信已授权 等提示, 然后把 code 码发到后台去做校验和保存,然后返回 绑定成功 或者 已绑定
最后,这个账号就成功绑定了微信登陆,可以使用微信进行扫码登陆了
扫码登陆过程是:
先在登陆界面点击扫码登陆按钮,主进程会弹出一个二维码页面,并且会监听这个页面 url 的变化
当用户使用微信扫码并且点击确定之后,页面 url 发生变化,触发 监听的回调函数,发送一个登陆请求
后端收到登陆请求后,会返回微信授权 code 码, 然后主进程把 授权code码 发给渲染进程
渲染进程拿到 code 码之后,再把 code 码发送到后台去进行验证,验证成功之后就返回了 token 和其他用户信息, 然后就完成了这个登陆过程,最后跳转到主界面
2、登陆鉴权
首先是在登录页面登录,输入用户名和密码,点击登陆就会发送一个登陆请求:
1、请求成功会返回这个账号的用户信息,这里可以写一个 hooks,在 hooks 里面获取 token 并且保存到 localStorage 和 pinia 中,然后通过 token 来获取用户的 权限编码 和 其他一些信息,最后跳转到主界面
2、当用户登录到主界面的时候,左侧菜单栏的数据是动态渲染的:
- 首先从接口获取到菜单数据,但菜单数据不符合我们前端多级菜单组件的格式要求,需要对数据进行重构
- 把数据重构成可以方便遍历访问的 二级菜单的数据格式
- 然后构造路由表,其中每一个路由对象都有 path,name,component等基本属性
- 通过 addRoute 方法,把 经过重构处理后的路由对象 动态添加到路由表中
- 登录成功之后,左侧的菜单栏就是根据 权限编码拿到的菜单数据动态加载的,
页面的路由表也是动态添加的;这样就保证了不同用户拥有不同的菜单访问权限,
比如超级管理员拥有全部的菜单数据(几百个页面),
而普通用户可能只有几个菜单(几十个页面),权限不同,访问范围也不一样。
然后在项目中,还可以对页面路由、按钮和超链接也进行这个权限控制
3、页面路由鉴权:判断用户如果没有对应的权限就不可以进入某个路由:
- 这个功能可以在 beforeEach 前置导航守卫里面做判断,判断用户的权限编码:
- 如果是超级管理员直接next 通行
- 如果不是超级管理员,需要拿到当前用户的所有路由信息来判断这个要跳转的路由地址是否存在,
如果存在,就跳转;如果不存在,就提示用户没有权限,并跳转到一个404错误页面
4、按钮级别权限:这个可以使用自定义指令来实现,流程大概是:
- 新建一个全局自定义指令 v-auth='某某权限字符',指令的判断逻辑是:
1、先判断指令有没有值
2、有就从pinia中拿到用户的权限信息,然后查找有没有这个指令值对应的权限信息
3、如果有就说明有权限,直接return结束判断;如果没有就删除这个元素本身
- 这样就实现了按钮级别的权限控制,有权限才会显示这个按钮,否则就不显示
5、最后总结一下,其实权限是通过 角色 来控制的:
- 给某个用户新增一个权限,就是给这个用户添加一个角色
- 给用户删除一个权限,就是在用户上删除一个角色
- 【可说可不说】角色的添加过程是:
1、在角色管理页面中点击角色新增按钮,请求获取菜单权限树
2、在菜单权限树中选择对应的权限,其实就是选择了某个权限的id
3、当点击【确认新增】,会给后端发送请求,传递 权限id 等这些参数
4、后端那边会把多个权限id,组合成一个 角色, 一个角色对应着这个由多个权限生成的 ID
5、这个用户就拥有了这个角色身份,然后就拥有了这些选中的权限
- 注意:如果当前用户正在使用这个角色来获得操作角色增删改的权限,
那么它直接删除这个角色后台会报引用资源错误
这就是我所做的这个 登录鉴权 的过程
3、界面全屏设置和兼容
可以使用浏览器的 Fullscreen API 来实现页面的全屏设置,但是各个浏览器的这个api不相同,因此需要检查浏览器是否支持
使用 if 判断各个浏览器对应的全屏api是否存在,然后再执行,这样可以实现在不同浏览器下的全屏效果,缩小回正常也是一样。
//目前是否是放大
var isFull=!!(document.webkitIsFullScreen || document.mozFullScreen ||
document.msFullscreenElement || document.fullscreenElement);
if( isFull ){//缩小
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}else{//放大
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
}
}
4、有做过即时通信吗?(有了解 socket \ websocket 吗?)
websocket 是一种全双工通信协议,客户端和服务器只需要一次握手就可以建立持久连接,进行双向数据传输
不仅客户端可以给服务器发送消息,服务器也可以主动向客户端发送消息,没有同源限制,实时性强,适用于实时通信、在线游戏、直播等场景
大概用法如下:
首先 new 一个 websocket: let ws = new WebSocket(url)
, 其中参数 url 是 ws://1270.0.0.1:9999
,协议标识符为 ws 或者 wss
连接成功后触发open事件,使用 ws.onopen(callback) 或者 ws.addEventListener('open', callback) 设置事件回调函数
通过 ws.send 方法可以发送消息给服务器,服务器发送消息过来会触发 message 事件
关闭连接触发 close 事件,连接失败就触发 error 事件
应用场景呢:
一个公司可以开发一个基于 websocket 的即时通信系统,这样每个员工的所有操作都有痕迹,出了问题可查
股票系统,请求的股票数据每秒都要刷新,延时要很低,服务器要不断地推送数据给客户端
5、性能优化
1. 前端性能优化的方向:
1、网络请求优化:
- 减少请求次数,合并一些重复的请求;
- 使用缓存、使用 CND 网络,提高获取数据的速度、同时也可以减轻服务器的压力;
2、CSS 优化:
- 减少标签和 id 选择器的使用,减少嵌套的使用,降低选择器的复杂度;
- 避免使用css表达式和通配符,还有滤镜,滤镜会阻塞渲染;
3、js 优化:
- 使用异步加载,防止阻塞渲染;
- 减少DOM访问、eval 和 闭包,减少重绘和回流操作;
4、数据的优化:
- 多使用 js和css 的外部文件方式引入项目,这样它们可以被浏览器缓存下来;
- 首页加载也要优化,多使用懒加载,按需加载;
- 图片等静态资源进行压缩,懒加载、还可以制作成雪碧图减少请求次数;
5、构建工具的配置优化:
我在项目中使用的是 vite 工具,可以进行一些配置,提高性能,比如:
1、对代码进行分包、压缩,使用按需加载;
2、配置 tree shaking 把没有使用到的代码删除掉,减少打包体积;
3、通过 CDN 引入第三方资源包 等等
2. 虚拟列表
相关面试题:首页加载的数据有 10 万条,怎么处理加载的问题?
1、分批获取数据:可以通过懒加载、分页方式
分页:点击下一页/页码的时候,再次发送请求 重新请求阶段数据
懒加载:监听滚动事件,触发事件 向后端请求数据 --> 阶段数据
缺点:增加请求数
2、一次性拿10万条数据:通过虚拟列表,分段加载到页面上,也就是只渲染看得见的部分
首先计算,数据的开始 和 结束位置以及每一屏的记录数,每一行的高度
通过计算属性,slice() 截取 需要加载的单屏的数据
计算单屏的高度 和 所有数据的总高度,然后监听滚动事件 计算滚动上去的行数,
计算滚动之后的开始和结束位置记录,然后使用CSS平移数据,实时更新可视区域的列表项
6、OSS 上传
之前的项目中使用了阿里的oss,首先要安装:npm install ali-oss
下载之后要进行一些配置,导入一个 OSS 类:import OSS from 'ali-oss'
然后 new 一个OSS实例并且传入一些初始化的参数:
export const client = new OSS({
bucket: '',
region: '',
accessKeyId: '',
accessKeySecret: '',
endpoint: '',
secure: ''
})
第一个参数是 bucket,存储空间的名称,还有 region 注册区域,keyID 访问ID、密钥 和 外网访问的区域节点 endpoint和是否开启 https协议 等等参数
以上就是这个阿里 oss 上传的一个使用过程
7、文件下载功能
下载文件是一个比较常见的功能,在我的那个 electron 项目里面就有下载功能, 比如系统日志、招生、班级、缴费、就业统计...等功能中就需要有一个导出的按钮,点击这个导出按钮, 就会发送一个请求到后端,后端会进行处理,生成一个文件,然后保存到文件系统或者阿里云 oss 服务器中, 然后会返回文件的 url 地址
因为这个项目是桌面软件,因此不能像网页端那样使用 a标签 来下载,需要调用系统api来下载并且保存到本地
整个流程就是:
前端页面是一个渲染进程,点击下载按钮,它会给主进程传递参数
然后由主进程创建新的窗口,这个新的窗口会另外打开一个下载文件列表的页面,选中一个文件点击下载
就会调用 https.get 方法去获取文件数据,同时主进程会执行打开一个 dialog
当 dialog 中用户选择了某个存储的地址后,会通过 fs.createWriteStream 创建生成新的文件,
文件内容就是由 https.get 请求回来的响应数据 res.pipe(file) ,通过管道往文件中写入内容,最后保存成功
8、项目打包
项目是使用 electron-vite 脚手架搭建的,electron 里面是嵌入了一个谷歌浏览器和nodejs, 因此即使是空项目打包也有40MB左右的大小,但是electron它的优势就是跨平台,开发快,因此大小并不是很重要
跨平台嘛,可以打包多个端,window、linux,macos 等这几个平台
首先,node版本不要太高,我设置的是16.9.0,太高会有很多兼容性的问题,并且解决方案可能会比较少
然后,打包成 windows 安装包就根据公司的要求来配置,比如是否可以选择安装目录,是否创建快捷方式,设置卸载的名称...
还有,windows 配置的图标是:build/icon.ico 、mac os 配置的图标是build/icon.icons
然后,appID 安装包的名称,项目的名称等
设置好 环境变量 进行打包即可 : npm run build:win. 、 npm run build:mac
打包出来的安装包文件,给后端人员去挂在下载网站上,最后可能还需要配置更新检查等等内容
appId: com.electron.app //包名
productName: 小鹿线CRM客户管理系统 //软件的名称
win:
executableName: electron-app //可执行文件
nsis:
artifactName: ${name}-${version}-setup.${ext} //安装包的名称和后缀
shortcutName: ${productName} //快捷方式的名称
uninstallDisplayName: ${productName} //卸载程序的名称
createDesktopShortcut: always //是否创建快捷方式
oneClick:false //一键安装
allowToChangeInstallationDirectory //是否可以选择安装目录
9、 目前项目使用的vue技术
1、全局混入:字典
2、自定义指令:判断按钮级权限控制
3、store + 持久化存储:刷新页面数据还在
10、项目打包上线到服务器,我怎么通过浏览器访问你的index页面
要通过浏览器访问 index 页面,需要先将网站打包并部署到服务器上,需要做以下几个步骤:
1、首先将网站代码打包成静态文件,例如使用 webpack、vite 等工具进行打包
2、将打包好的静态文件上传到服务器上,可以使用 FTP、终端ssh连接 等方式进行上传
3、在服务器上安装并配置 Web 服务器软件,例如 Apache、Nginx 等, 需要在 Web 服务器上配置虚拟主机,将域名或 IP 地址与上传的文件夹路径进行一个绑定
4、在 DNS 服务商那里将域名或 IP 地址解析到这个服务器上。如果使用的是域名, 需要在 DNS 设置中添加 A 记录或 CNAME 记录,将域名解析到服务器的 IP 地址上
5、配置好了之后,就在浏览器中输入域名或 IP 地址,就可以访问项目的页面了
方法有很多,不同的web软件和操作系统有对应的不同方法,可以参考相关的文档和教程
11、说一下最近开发的一个项目业务背景和架构和技术栈
我最近开发的项目是这个 CRM客户管理系统,产品类型属于软件级桌面应用,针对教培行业对于客户管理的工作流的实现;
从流量入口、录入客户、公海、然后到报名、学习、教学和系统管理,财务管理等模块,组成一个完整的工作流
开发的技术,前端这边是 electron 结合 vue3 和 ts 来做的,包括 pinia、element-plus、ucharts等插件,后端那边使用 java 来做的
我独立负责这个项目的前端开发,从 0 到 1 的项目搭建,做了常量 config 全局配置、字典混入的封装、从登录开始到进入后台的 权限验证和按钮级别的验证,并且对 axios 封装了 get 和 post 请求,项目的数据存放到 pinia 中进行管理 等等
以上就是我这个项目构建过程以及大概情况
追问
一、对项目代码哪些方面进行优化?
1.使用keep-alive缓存不活动的组件
2.使用懒加载路由
3.使用vue-lazyload实现图片懒加载
4.使用防抖节流函数
5.v-for 遍历添加key,且避免同时使用 v-if
二、封装哪些组件,为什么封装组件
1.图片上传组件
2.富文本编辑器组件
3.分页器组件等
封装组件的主要原因是为了提高代码的可重用性和可维护性。用起来方便一点,将一些常用的功能封装成组件, 可以在不同项目中复用这些组件,从而减少重复代码的编写,提高代码的复用性和开发效率。
封装组件还可以使代码进行模块化管理,更容易维护和扩展。当某个组件需要修改时,只需要修改这个组件的代码,而不需要修改整个应用程序的代码
三、为什么对axios进行二次封装?
api统一管理,不管接口有多少,所有的接口都可以非常清晰,容易维护。
可以统一url配置,统一api请求,在请求拦截器、响应拦截器 中对 http错误码 和 自定义的code码进行统一处理
四、怎么区分开发、测试、生产环境
在vite中,在src同级目录下创建 .env.development、.env.production、.env.test文件,分别对应开发、生产、测试环境。
在这些文件中,可以定义一些环境变量,比如接口地址等,然后在项目中通过i
如果在配置文件中使用需要引入loadEnv函数,然后通过loadEnv(mode, process.cwd(),'')来获取环境变量。
在设置server的时候,可以通过p
12、你的组件是如何划分的?
在vue项目中,组件可以划分为两种类型:容器组件和展示组件
容器组件是一个容器性质的组件,我们可以把它理解为最外层的父组件,也就是最顶层的组件, 一般我们把它放置在 views 新建一个 layout 文件夹,其功能主要用于做数据提取与实现公共逻辑,然后渲染对应的子组件
另一类组件叫做展示组件,字面意思就是主要用于做展示的组件, 其主要功能是负责接收从容器组件传输过来的数据并在页面上渲染,实现其内部独有的功能逻辑
13、用户列表中,分页组件是怎么使用的?
1、先安装分页组件库,在vue中引入和注册分页组件
2、一般是定义当前页码、每页显示数量、数据总量total 等数据,以及绑定切换页码、更新数据等方法
3、将数据和方法绑定到分页组件中,以便分页组件能够正确显示和响应用户操作
但是我使用的是 element-plus 组件库中的分页组件,使用方法还是比较简单的,官方文档描述的很详细了
14、数据发生变化,视图没有更新
在Vue.js中,当数据发生变化,视图没有更新的情况可能是由于以下原因导致的:
1、Vue.js的DOM更新是异步的,如果在一个异步操作中修改了数据,Vue可能无法立即检测到数据的变化 可以使用 this.$nextTick()
方法,这样可以获取到最新的数据和DOM元素,然后再去修改数据触发视图更新
2、动态给对象新增属性或者删除属性 和 通过数组下标修改数组中的元素或者手动修改数组的长度 是不会触发视图刷新的, Vue识别不到,解决方法是使用 this.$set()
强制更新
15、项目中发现的难点或者常见的问题
1、对业务的理解
现在都是前后端分离的项目,很多业务逻辑开始往前端这里转移。而且有时候需求不明确,就需要我们对业务有一定的了解; 知道客户需要什么才能去写合适的业务逻辑。 而且其实业务最多变的就是业务逻辑,如何设计好才能满足业务逻辑变的需求,也是一个很难的事情。
2、计算机基础知识
比如计算机网络:CDN、网络接入层、API网关、存储系统、代理、cookies、socket等等的专业术语。一听可能就有很多人蒙圈了 很多时候只是开发页面很简单,但是出现问题了,因为问题是在前端表现出来的,很有可能需要前端第一时间去定位问题点,这就需要计算机基础知识比较扎实 才能找到问题的解决方案
3、工程化
只是写一个页面可能不难,但是前端由于能力的增加,越来越多的前端工作开始接触到工程化的问题。 如何让各个分散的页面变成可以互相配合契合业务,如何公用代码,如何设计架构等等,这也是一个需要时间积累的能力
4、优化兼容
因为前端是直接和用户接触的界面,性能好坏影响很大,但是前端优化兼容又是一条慢慢长路,从CSS到JS再到网络,再到后台优化
后端最难的可能也是优化、优化算法、优化数据库、优化响应时间等
前端方面也是一些算法优化、渲染优化、针对浏览器优化、还有兼容问题,我觉得这也算是一个难点
16、遇到bug解决方案
在项目中,不同的 bug 有不同的解决方法,千奇百怪。但是,我们可以总结出一些通用的解决方法:
定位到发生 bug 的位置,然后找出原因,修复它;
如果找不到 bug 的原因,可以尝试使用浏览器调试工具来定位问题,或者回退上一个版本,慢慢找差异,定位问题;
如果无法修复 bug,可以考虑使用临时解决方案,比如添加一个错误提示或者禁用某个功能。
17、js跟ts的区别
1、JavaScript 是一种动态类型语言,而 TypeScript 是一种静态类型语言;
2、JavaScript 可以直接在浏览器中运行,而 TypeScript 需要先编译成 JavaScript 才能在浏览器中运行;
3、TypeScript 支持 ES6+ 的所有特性,而 JavaScript 只支持部分特性;
4、TypeScript 可以在编译时检查类型错误,而 JavaScript 只能在运行时检查类型错误;
5、使用 TypeScript 可以提高代码的可读性和可维护性。
18、怎么防止恶意登录?
恶意登录是一种常见的网络攻击,可以通过多种方式来防止。例如:
使用拦截器 Interceptor 来限制登录,以防止未登录用户直接访问后台页面;
使用令牌机制来防止恶意登录;
定期修改账户密码,尽量设置复杂的密码,不要使用弱密码;
关闭不必要的端口和服务,安装杀毒软件或防火墙来抵御攻击;
不建议在服务器上安装过多的软件。
19、移动端和pc端登录时,对方能有提示
1、可以使用 webSocket:
WebSocket用于在Web浏览器和服务器之间进行任意的双向数据传输的一种技术,基于TCP协议实现,包含初始的握手过程, 以及后续的多次数据帧双向传输过程。
其目的是在WebSocket应用和WebSocket服务器进行频繁双向通信
当用户在移动端登陆的时候,登录成功后,可以向服务器传递一个状态值,表示已经登录了,然后通过websocket
向pc端推送消息,告知pc端,你已经在移动端登录了,反之则向移动端推送消息
3、还可以使用请求轮询,每隔一段时间发送请求去查询是否有其他设备或者其他地方登陆
20、你们公司用的权限框架是什么
我们公司用到的权限框架是:若依开源框架(RuoYi),是一套后端基于java的开源框架
包含了权限系统的所有功能:
1、用户、角色、部门、岗位、菜单、系统设置、日志等所需的所有功能,
2、目的让开发者注重专注业务,降低技术难度,缩短项目周期,
3、RuoYi官网 登录账号:admin ,密码:admin123,在线演示可以看到demo
追问:
在写权限框架时遇到了哪些困难?
21、CRM客户管理系统项目亮点
项目第一版完成之后,就进行了项目的性能优化,
一、采用缓存来加载数据,包括分页加载,懒加载,数据压缩,合并请求,数据缓存
1.分页加载:将数据分成多个页面进行加载,这样可以减少单个页面中的数据量,降低加载压力;
2.懒加载:在用户滚动页面时才加载数据,而不是一次性将所有数据都加载出来。这种方式能够减少页面初始加载的数据量;
3.数据压缩:对于一些文本数据可以使用压缩算法, 将数据压缩后再传输到前端,减少传输的数据量;
4.合并请求:将多个请求合并成一个请求, 减少请求次数和传输数据量;
5.数据缓存:对于一些不常变化的数据,可以在前端使用本地缓存来提高访问速度;
二、其他方面的优化,比如:
1.减少http请求
2.使用浏览器缓存,减少请求事件
3.延迟加载组件(懒加载,避免一次请求过多组件导致页面卡顿)
4.使用webpack对js css打包,减少文件大小提高加载速度
三、完整的业务流
22、大文件上传
在之前的项目中就做了这个大文件上传的需求,支持切片、断点续传、错误重试 等等
这个具体流程就是:
1、首先用户在点击按钮或者选择文件之后,就会禁用上传按钮,防止多次点击,并且会获取选择的文件;
2、使用 FileReader 对象的 readAsArrayBuffer 方法读取文件内容为 ArrayBuffer, 并用SparkMD5库计算文件内容的MD5哈希值,结合文件后缀生成唯一文件名;
3、调用后端方法获取已上传切片信息,存入数组或声明空数组作为待上传切片;
4、根据文件大小确定切片大小和数量,可设定为每次 100KB 或动态计算,然后可以设置最多 100份;
5、将文件切片,生成切片信息对象并加入一个数组里面;
6、使用 FormData 逐个上传切片数据至后端,当所有切片上传完成,会请求后端合并切片为一个完整文件;
可以使用 Promise 和 async/await 保证顺序和状态,通过哈希值确保数据完整性,实现分片上传提升速度和稳定性。
23、Vue 中如何使用自定义指令封装一个水印功能
1、获取目标元素的宽度和高度,使用 el.clientWidth 和 el.clientHeight;
2、设置目标元素的定位属性为relative,以便相对定位水印元素;
3、 创建一个 span 元素作为水印模板。使用 span.style 设定水印元素的样式,包括字体、颜色、大小、位置、旋转等;
4、嵌套循环遍历目标元素的宽度和高度,在每个位置创建水印元素的克隆并通过el.appendChild(cloneSpan)附加到目标元素;
5、在Vue模板中使用v-watermark指令,传递参数,可在任何元素上添加水印。
24、怎么解决长时间保存token的安全问题? 认证失败的请求怎么重新发送?(token过期怎么办?)
一、可以使用双 token 安全的刷新 token 实现长期保存 token
双 Token 方案是一种常见的安全策略,用于解决长时间保留 Token 导致的安全问题。该方案同时优化了用户体验, 并且可以储存失败请求并在刷新 accessToken 后重新请求这部分接口
采用双 Token 方案的话,在登录后获取短期的 accessToken 和长期的 refreshToken,accessToken 有效期短,refreshToken 有效期长, 在 accessToken 过期后,通过 refreshToken 获取新的 accessToken
这个方案的优点是:
1、提升安全性
accessToken 的有效性比较短,即使被盗用,攻击者的非法访问会受到时间限制,因为其在有效期结束后会自动失效
refreshToken 是长期有效性,需要在客户端安全储存,但即使 refreshToken 被窃取,攻击者也无法直接访问敏感信息, 因为 refreshToken 不可直接用于资源访问
2、用户体验比较好
- refreshToken 的有效性长,可以允许用户在较长时间内都保持登录状态,从而改善了用户体验
二、刷新 accessToken 的过程
当 accessToken 过期时,客户端如果请求受保护资源会返回未授权响应。此时,使用 refreshToken 向认证服务器请求新的accessToken认证, 服务器验证 refreshToken 有效后,发放新的 accessToken 给客户端并重置它的有效期。 如果 refreshToken 也过期或被撤销,客户端就需要重新登录以获取新的 refreshToken
三、储存失败请求,并刷新 accessToken
刚刚说的,当 accessToken 过期且客户端尝试访问受保护资源时,会返回未授权响应。此时客户端可以保存该请求,包括相关信息和参数; 在刷新accessToken后,客户端重新发送之前保存的失败请求,此次请求将获得授权; 这确保用户在重新登录后不会受之前请求失败的影响,同时可以保障受保护资源的安全性。
四、实现双 Token 方案时,需要注意以下安全问题:
1、在传输 accessToken 和 refreshToken 时,务必使用安全的方式(如 HTTPS),以避免拦截或劫持
2、为防止恶意应用程序或攻击者获取,必须安全地储存这些令牌
25、小程序怎么适配 iPhone 以及 Android 的底部导航横条
iPhone X 以上版本取消了 home 按键,然后用底部的一个小黑条来代替,所以需要使用适配 iPhone X 的布局约束 来确保界面元素不会被底部小黑条覆盖:
1、在创建约束时,考虑到 底部安全区域 的高度,以便界面元素不会被遮挡;
2、避免将重要的交互元素放置在底部小黑条的位置,以免用户无法轻松访问;尽量将重要的按钮和操作放置在屏幕的中间或上方区域;
3、对于底部导航栏或标签栏等底部固定的元素,确保其高度和位置正确适应底部小黑条;可以使用自动布局或调整视图的布局约束来实现;
4、当出现全屏内容、图片或视频时,确保它们的底部不会被底部小黑条遮挡;
5、在显示全屏内容时,可以将内容的底部边缘与屏幕底部对齐,以确保内容完整显示。
代码就是:
获取底部安全区域的高度,然后通过 整个屏幕高度 减去 安全区域高度 来计算实际使用的底部区域的高度;
通过 createElement('div') 创建div元素,设置为 fixed 定位,放到底部,这样就可以遮住底部区域,防止点击小黑条时触发页面交互
以上,就是这个底部导航条的适配过程
26、首页加载大量数据怎么保证不出现长时间白屏
首页因为一次性加载大量数据导致卡顿,任务太多了,所以出现白屏,采用预加载机制,优先加载本地缓存信息,提高用户体验, 并通过路由懒加载、优化静态资源引入方式、分包等处理方式实现首屏加载性能提升,优化前 2.5s,优化后 0.8s,实现了秒开效果
1、预加载机制: 预加载机制可以将页面需要的资源提前加载到本地缓存中,当用户访问相应页面时, 可以直接从缓存中获取资源,减少了网络请求的时间,加快了页面的加载速度
2、路由懒加载: 可以将页面的代码按需加载,当用户浏览到某个路由时才进行加载,这样可以减少首次加载的资源量,提高页面加载速度。
3、优化静态资源引入方式: 是指使用合适的方式引入静态资源,如将CSS放在头部加载,JavaScript放在底部加载,避免资源阻塞,提高页面加载效率。
4、分包: 则是指将页面的代码按照功能模块进行划分,使得首屏只加载必要的模块,其他模块可以延迟加载,在需要时再进行加载,从而降低了首屏加载的时间
但是可能会遇到一些问题,比如:
1、兼容性问题: 确保预加载机制和路由懒加载的兼容性测试,提供替代方案或回退策略以适应不支持的浏览器。
2、资源体积过大: 除了资源优化,考虑压缩、延迟加载等减少初始加载负担的策略。
3、网络延迟和带宽限制: 使用CDN、压缩算法、缓存等来改善网络连接较差时的加载性能。
4、代码质量和结构问题: 优化加载性能不仅靠工具和技术,也需要关注代码质量、结构,避免冗余和性能问题。
5、用户体验权衡: 在优化加载性能时需平衡用户体验,避免过度延迟加载引起的闪烁或卡顿问题,根据情况调整优化策略。
27、ECharts 图表怎么实时刷新数据
在项目中我通过使用 ECharts 生成可视化图表来生动地展示数据,增强了数据分析的直观性。 同时,为了实现图表信息的动态刷新功能,我通过 WebSocket 与后台服务器进行实时通信,从而获取最新的数据。 这样一来,图表能够在数据更新时自动刷新,展示最新的信息,保持了数据展示的实时性和准确性
28、前端优化
1、css优化: 减少标签和id选择器的使用 减少派生选择器,例如 #dv ui li{} 选择器是从右向左查询的 避免使用css表达式 避免使用滤镜,滤镜会阻塞渲染
2、js优化:
尽量减少DOM访问
更多异步操作编译,同步会导致代码阻塞
减少使用eval和闭包,
尽量使用css3动替代js动画
缓存做处理
3、webpack优化:
配置Loader时通过 include去减少路径查询
使用 HappyPack,loader文件转换消耗巨大,HappyPack把这部分任务分到多个进程去并行处理
压缩css js 和 html代码
采用cdn加速
使用 Tree Shaking去除多余代码
按需加载
4、其他优化:
图片懒加载
使用base64
雪碧图
在实际开发中通过使用上述优化方案,使项目的FCP从7s降到了2s。 注:FCP是首次有效绘制时间,首次有效绘制时间是指浏览器在加载页面时,
在加载页面所必须的资源(图片,js,css等)加载完成并执行js代码后,在页面首次绘制之前所需要的时间。
追问:vue性能优化