一. 封装请求基地址
在src目录下面建一个api文件夹
然后在文件夹里面新建一个专门放用户请求的use.js
用axios发送请求
在use.js文件夹里导入request
在src目录新建发送请求的页面并导入封装好的请求
然后把这个请求封装成一个函数,这个函数里需要传入两个参数。
二.添加请求拦截器并设置请求头
一.拦截器介绍:
一般在使用axios时,会用到拦截器的功能,一般分为两种:请求拦截器、响应拦截器
请求拦截器: 在请求发送前进行必要操作处理,例如添加统一cookie、请求体加验证、设置请求头等,相当于是对每个接口里相同操作的一个封装
响应拦截器: 响应拦截器也是如此功能,只是在请求得到响应之后,对响应体的一些处理,通常是数据统一处理等,也常来判断登录失效等
// 请求拦截器
instance.interceptors.request.use(req=>{}, err=>{});
// 响应拦截器
instance.interceptors.reponse.use(req=>{}, err=>{});
从上可以看出,instance依然是第二步中创建的实例,然后对其进行拦截,请求用request,响应用reponse,二者都有两个配置项,一个是成功配置,一个是error配置。
拦截器的安装
1、安装 axios , 命令: npm install axios --save-dev
2、在根目录的config目录下新建文件 axios.js ,内容如下:
import axios from 'axios'
// 配置默认的host,假如你的API host是:http://api.htmlx.club
axios.defaults.baseURL = 'http://api.htmlx.club'
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error)
});
3、在main.js中进行引用,并配置一个别名($ajax)来进行调用:
import axios from 'axios'
import '../config/axios'Vue.prototype.$ajax = axios
请求头的设置
如;
// 2.open
xhr.open('POST', 'http://localhost:8000/server');
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 3.发送(可任意写法)
xhr.send('a=100&b=100');
Content-Type是属性名,application/x-www-form-urlencoded是设置的值。
这是自带的属性名,如果需要自己设置属性名,则需要在server.js中将接受所有请求头打开
response.setHeader('Access-Control-Allow-Headers', '*');
由于还会发送一个OPTIONS请求,所以还需要在server.js中设置all方法接收任何类型的请求。
app.all('/server', (request, response) => {
});
如图:
token过期问题处理
对于token过期,有两种方案:
方案一:当我们操作某个需要token作为请求头的接口时,返回的数据错误error.response.status === 401,说明我们的token已经过期了。
我们希望当响应返回的数据是401身份过期时,让当前浏览页面强行跳转到登入页面,让用户手动更新token。拿到最新的token值后再跳回之前浏览的页面。增强用户体验。
实现原理:
在阻拦响应器中配置:
// 阻拦响应器
request.interceptors.response.use(function (response) {
return response
}, async function (error) {
if (error.response && error.response.status === 401) {
// token续签方式1:
//清空当前vuex保存的token(我们这的vuex和本地已经建立了关系,相当于也清空了本地token)
store.commit('upUser', '')
console.log(router.currentRoute.fullPath)// 当前路由的完整路径(#后面的)
//这里我们采用?path=的方式保存当前浏览页面的完整路径,
// push()会产生历史记录 而replace不会有历史记录
router.push({ path: `/login?path=${router.currentRoute.fullPath}` })
}
return Promise.reject(error)
})
登入组件中给登入功能函数添加:
this.$router.replace({
path: this.$route.query.path || '/'
})
// 1.点击登入
async onSubmit () {
try {
const { data: res } = await loginAPI(this.user)
//登录成功
// 不严谨的返回上次浏览的页面
// this.$router.back()
// 推荐方式:
// 登录后, 判断有未遂地址(有未遂地址的情况是:token过期,在阻拦响应器中实现对未遂地址的保存), 登入成功后跳转到未遂地址, 否则去/路径(跳到首页--这种情况是:用户主动前往登入页面的登入,没有未遂地址,登入成功后直接前往首页)
// replace不会产生路由历史记录
this.$router.replace({
path: this.$route.query.path || '/'
})
// 存储获取过来的token
this.$store.commit('upUser', res.data)
} catch (err) {
console.log(err)
if (err.response.status === 400) {
this.$toast.fail('手机号或验证码错误')
} else {
this.$toast.fail('登入失败,请稍后再试') // 可能由于网络问题导致的登入失败
}
}
},
方案二:实现用户无感知的刷新token值,我们希望当响应返回的数据是401身份过期时,响应阻拦器自动帮我们刷新token值,而不是让用户手动更新token。拿到最新的token值后再重新发起刚刚因token过期的请求。从而实现无感知
登入后后台接口返回值要求:提供刷新token的令牌,并且后台提供了刷新token的接口: (请求头要求是refresh_token)
注意:1. 在请求响应器中做判断在非刷新token的时候,给请求头配置token,而刷新token的时候,我们自己手动添加请求头为refresh_token
2.refresh_token也有过期的时候,这时只能强行让用户自己重新登入
// 刷新用户token
export const updataTokenAPI = function () {
return request({
method: 'PUT',
url: '/v1_0/authorizations',
headers: {
Authorization: `Bearer ${store.state.user.refresh_token}`
}
})
}