每个请求都需要携带 token ,所以我们可以使用 axios request 拦截器,在这里,我们给每个请求都加 token,这样就可以节省每个请求再一次次的复制粘贴代码。
token 失效问题,当我们token 失效,我们服务端会返回一个特定的错误表示,比如 token invalid,但是我们不能在每个请求之后去做刷新 token 的操作呀,所以这里我们就用 axios response 拦截器,我们统一处理所有请求成功之后响应过来的数据,然后对特殊数据进行处理,其他的正常分发。
// 给axios添加一个请求拦截器,
axios.interceptors.request.use(config =>{
// 为请求头添加一个Authorization属性,值为token
// 这样后,当你请求别的接口时服务器就会先判断你的请求头中有没有Authorization这个属性,
// 如果没有,就会驳回你的请求.
config.headers.Authorization = window.sessionStorage.getItem('token');
// 在最后必须return一个cofig
return config
})
axios二次封装
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import storage from './storage'
import config from '@/config/index'
import router from '@/router/index'
// 创建axios对象,并设置请求信息,用于设置请求拦截器
const service = axios.create({
// 配置请求基础地址
baseURL: config.baseApi,
// 设置请求超时时间
timeout: 5000
})
// 请求拦截
service.interceptors.request.use(
res => {
// 在每一次请求时携带上token
const Token = storage.getItem('Token')
if (Token) {
res.headers.Token = Token
}
return res
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
service.interceptors.response.use(
res => {
const { code, data, message } = res.data
// token未过期时,返回的数据
if (code === 200) {
return data
} else {
// token过期时返回的数据
if (code === 401) {
MessageBox.alert('登录已过期,请重新登录!')
router.push({ path: '/' })
} else if (code === 403) {
MessageBox.alert('您没有访问权限')
} else if (code === 404) {
MessageBox.alert('访问失败,请检查网络')
} else if (code === undefined) {
return res.data
} else {
MessageBox.alert(message, '警告', {
confirmButtonClass: 'el-button--myPrimary',
type: 'warning'
})
}
return Promise.reject(new Error('error'))
}
},
error => {
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
// 封装request请求
function request (options) {
// 设置默认数据
options.method = options.method || 'get'
options.baseURL = options.baseURL || ''
if (options.method.toLowerCase() === 'get') {
options.params = options.data
}
// if (config.env === 'prod') {
// service.defaults.baseURL = config.baseApi
// } else {
// service.defaults.baseURL = config.mock ? config.mockApi : config.baseApi
// }
// 设置基础路径地址,根据不同的接口设置不同的基础路径
service.defaults.baseURL = options.baseURL
// 将数据传递给axios对象,并返回
return service(options)
}
// 给request对象创建不同类型的函数,这样使用时就可以通过request.get(url, data, options){}的方式使用
['get', 'post', 'put', 'delete', 'patch'].forEach(item => {
request[item] = (url, data, options) => {
//返回一个请求接口对象
return request({
url,
data,
method: item,
...options
})
}
})
// 导出axios对象,二次封装后的对象
export default request
自动刷新token
Vue.use(Vuex)
Vue.use(VueAxios, axios)
Vue.use(qs)
注:qs,。
在 request 拦截器实现
axios.interceptors.request.use(
config => {
config.baseURL = '/api/'
config.withCredentials = true // 允许携带token ,这个是解决跨域产生的相关问题
config.timeout = 6000
let token = sessionStorage.getItem('access_token')
let csrf = store.getters.csrf
if (token) {
config.headers = {
'access-token': token,
'Content-Type': 'application/x-www-form-urlencoded'
}
}
if (config.url === 'refresh') {
config.headers = {
'refresh-token': sessionStorage.getItem('refresh_token'),
'Content-Type': 'application/x-www-form-urlencoded'
}
}
return config
},
error => {
return Promise.reject(error)
}
)
//在 response 拦截器实现
axios.interceptors.response.use(
response => {
// 定时刷新access-token
if (!response.data.value && response.data.data.message === 'token invalid') {
// 刷新token
store.dispatch('refresh').then(response => {
sessionStorage.setItem('access_token', response.data)
}).catch(error => {
throw new Error('token刷新' + error)
})
}
return response
},
error => {
return Promise.reject(error)
}
)