项目初始化--重构
- 删除不必要文件,留下一个简单框架
登录页改造
背景图平铺整个页面
修改检验规则,手机号,密码
接入登录接口API
解决跨域问题
1. 什么是跨域?
在A地址(发起请求的页面地址)向B地址(要请求的目标页面地址)发起请求时, 如果A地址和B地址在: 协议 、域名、 端口 不全相同,则说明请求是跨域的
2. 跨域报错的原因
请求是跨域的,并不一定会报错。普通的图片请求、css文件请求是不会报错的
3. 跨域请求出现错误的条件
浏览器同源策略 && 请求是ajax类型
浏览器同源策略,同源策略是一个重要的安全策略,它能帮助阻隔恶意文档,减少可能被攻击的媒介。
4. 解决方案
- jsonp方式
- 后端开启cors
- 代理转发的方式
5. 如何实现代理转发
- vue脚手架项目内置了代理转发功能
- 前端浏览器直接跨域访问后端服务器不行
- 前端浏览器请求本地开启cors的中间服务器, 它再去请求真正接口服务器
- vue-cli 解决跨域配置说明
在vue.config.js配置文件中,有一项是devServer,它就是我们下边要操作的主角。
==注意1: 一定要把.env.development里设置为/api, 让它触发webpack开发服务器作为的代理服务器使用==
# 开发环境的基础地址
VUE_APP_BASE_API = '/api'
- 在
vue.config.js中,配置如下
module.exports = {
devServer: {// 里面新增
// before: require('./mock/mock-server.js'), // 注释线上地址
// 代理配置
proxy: {
// 这里的 api 表示如果我们的请求地址以 /api 开头的时候,就出触发代理机制
'/api': {
target: 'http://ihrm.itheima.net', // 需要代理的地址
changeOrigin: true // 是否跨域,需要设置此值为 true 才可以让本地服务代理我们发出请求
}
// 这里没有pathRewrite, 因为后端接口就是ihrm.itheima.net/api这种格式,所以不需要重写
}
}
}
axios的相应拦截器
问题
-
后端可以用http状态码, 来返回标记错误提示, 例如
- 400 -> 前端参数错误
- 401 -> 用户身份过期
- 403 -> 用户无权限
- 404 -> 请求地址错误
- 405 -> 请求方式错误
-
后端也可以清一色全用200, 作为http响应状态码, 用success或code字段标记请求成功/失败
如果后端返回的状态码都是200,那么在调用接口时使用
try/catch,就无法进入catch逻辑
axios内部判定http状态码为4xx, 5xx才会抛出错误, 让catch捕获
解决
在
request.js中的响应拦截器中,对response返回的数据(success)进行判断
service.interceptors.response.use(
response => {
const { success, message } = response.data
if (success) {
return response
} else {
return Promise.reject(new Error(message)) // 返回Promise错误的对象, 等同reject() -> 自己根据success字段判断逻辑错误(账号密码错误)
}
},
error => {
return Promise.reject(error)
}
)
返回代码冗余问题
在
request.js文件的响应拦截器中,将成功返回设为为return response.data
token处理-axios请求拦截器-统一注入
原因
除了登录接口无需携带token, 因为这个是后台数据管理系统, 必须登录才能看到其他接口数据
解决
在axios请求拦截器统一携带token
src/utils/request.js, 添加请求拦截器代码
import store from '@/store'
service.interceptors.request.use(
config => {
// 知识点: js文件中能否使用this.$store?
// 不能, 因为这个this关键字不是Vue组件对象, 无法查找原型链上$store
// 但是this.$store为了拿到的是store/index.js导出store对象
// 解决: 我们直接把store对象导入过来使用, 是同一个store对象
const token = store.getters.token
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
token 处理-持久化
原因
现在 token 虽然保存在 vuex 中,但页面刷新之后,vuex 的内容丢失了,将会导致接口访问异常。所以我们需要对 token 做持久化处理,让页面刷新之后 token 不丢失。
解决
在 utils 文件夹中新建一个 auth.js 文件,封装 token 的获取,设置,删除方法。而后在 vuex 中调用
路由导航守卫
-
什么是导航守卫
- 导航守卫就是路由跳转过程中的一些钩子函数,在函数中通过跳转或取消的方式守卫导航
-
全局导航守卫分为几种
- 前置导航守卫 router.beforeEach
- 后置导航守卫 router.afterEach
- 登录状态下有token, 如果用户去登录页, 强制回到首页
- 非登录状态下无token, 去白名单页面, 放行, 其他页面需要登录才能查看
页面跳转进度条
在beforeEach中启动进度条,在afterEach中停止进度条
注意
在全局路由守卫中可能会走next('/重定向地址'), 导致路由跳转中断, 重新进行路由跳转和守卫重新执行, 所以在重定向位置, 需要把进度条关闭, 否则进度条会一直存在
获取用户信息
- 用户名是如何管理的?
- 在vuex定义相关变量和mutations和actions
- 在路由页面切换时, 判断如果vuex里无值, 就进行获取
在全局前置路由守卫调用api接口,因为需要用户一开始就能看见自己的信息。如果vuex没有name,就获取
身份过期处理
// 相应拦截器
service.interceptors.response.use(
response => {
// ...
},
error => {
Message.error(error.response.data.message) // http状态码4xx
if (error.response.data.code === 1002) { // token过期了
// 清空用户信息
store.commit('user/RESET_STATE')
store.commit('user/REMOVE_TOKEN')
router.replace('/login')
}
return Promise.reject(error)
}
)
获取用户头像
用户头像在一个新api接口中,调用后的数据要与前面保存好的用户信息合并
const actions = {
// 获取用户信息
async getUserInfo({ commit }) {
// 用结构赋值, 把data的值保存到左边变量
const { data: userObj } = await getUserProfileAPI()
const { data: avatarObj } = await getUserAvatarAPI(userObj.userId)
// console.log(userObj)
const newObj = { ...userObj, ...avatarObj } // 合并用户信息
commit('SET_USER', newObj)
}
}
登录未遂
目标
在退出时,跳回login时,回传当前的路径
- 点击退出跳转到登录页时,保存当前页面的完整路径
// 保存页面用户退出的地址,方便下次用户登录回到该地址
// redirect 是自定义的,路径后边是A=B的形式
this.$router.replace(`/login?redirect=${this.$route.fullPath}`)
- 回到登录页后,重新登陆的路由跳转
// 在登录页面,判断如果url上有参数, 用参数跳转, 否则去首页
this.$router.replace(this.redirect || '/')