在最美好的年华,没有遇到爱情,只遇到了疫情
应用环境,当我们项目中使用模糊匹配查询列表的时候,输入框中输入关键字,我们就会根据关键字调接口查询数据,如果输入的很快,接口反应不是很快,那么就会出现搜索出来的数据和输入的关键字不匹配的情况。这时候我们就需要配置axios请求的CancelToken来取消还没有响应完的接口,直接根据最新输入查询接口,匹配最新的结果
引入axios定义需要的变量
// 引入axios
import axios from 'axios'
...
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken
在请求拦截器中配置
// 取消请求
if (promiseArr[config.url]) {
promiseArr[config.url]('操作取消')
promiseArr[config.url] = cancel
} else {
promiseArr[config.url] = cancel
}
在get/post/put请求中配置
...
axios.get(url, {
params: params,
cancelToken: new CancelToken(c => {
cancel = c
})
}).then(res => {
...
axios.post(
url,
params,
{
cancelToken: new CancelToken(c => {
cancel = c
})
}
).then(res => {
vue中axios封装完整代码
// 引入axios
import axios from 'axios'
// 引入qs模块,用来序列化post类型的数据,后面会提到
// import QS from 'qs'
import store from '@/store/index'
import router from '@/router/index'
// elementUi提示组件。
import { Message } from 'element-ui'
// import {LoadingBar} from 'iview'
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken
// 环境的切换
console.log(process.env.NODE_ENV, process.env.ENV_CONFIG, '环境参数')
if (process.env.NODE_ENV === 'development') {
console.log(router, store, 'http.js中的路由器信息')
axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'testing') {
axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = 'https://www.bangying.tech/api'
}
// 设置请求最大时长
axios.defaults.timeout = 50000
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
axios.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'
axios.defaults.headers.common['By-User-Info'] = localStorage.getItem('userInfo_admin') ? JSON.parse(localStorage.getItem('userInfo_admin')).user_id : ''
axios.defaults.withCredentials = true
// 请求拦截器
axios.interceptors.request.use(config => {
// 如果不是登录接口,或者微信分享接口,都需要验证token, 隐私策略
// if (window.location.hash.indexOf('login') === -1 && window.location.hash.indexOf('wechat-share') === -1 && window.location.hash.indexOf('private') === -1) {
// const token = store.state.userInfo.Authorization
// token && (config.headers.Authorization = token)
// }
// 取消请求
if (promiseArr[config.url]) {
promiseArr[config.url]('操作取消')
promiseArr[config.url] = cancel
} else {
promiseArr[config.url] = cancel
}
// 配置request请求头header中的Authorization,如果登陆了就有Authorization就设置一下
if (store.state.userInfo && store.state.userInfo.Authorization) {
const token = store.state.userInfo.Authorization
token && (config.headers.Authorization = token)
}
return config
}, error => {
Message.error({
message: '请求接口出错',
duration: 3000
})
return Promise.error(error)
})
// 响应拦截器
axios.interceptors.response.use(response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
return Promise.resolve(response)
} else {
return Promise.reject(response)
}
}, error => {
if (error.response.status) {
switch (error.response.status) {
// 401: 未登录
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
// Message.error({
// message: '无权限',
// duration: 1000
// })
// window.location.href = store.getters.base_url + 'new-home/#/login'
// router.replace({name: 'login'})
break
// 403 token过期
// 登录过期对用户进行提示
// 清除本地token和清空vuex中token对象
// 跳转登录页面
case 403:
// Message.error({
// message: '登录过期,请重新登录',
// duration: 1000
// })
// 清除token
// localStorage.removeItem('token')
// store.commit('loginSuccess', null)
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
// window.location.href = store.getters.base_url + 'new-home/#/login'
localStorage.clear()
store.dispatch('loginOut')
break
// 404请求不存在
case 404:
Message.error({
message: '网络请求不存在',
duration: 1500
})
break
// 其他错误,直接抛出错误提示
default: {
// Message.error({
// message: error.response.data.message,
// duration: 1500
// })
}
}
return Promise.reject(error.response)
}
})
export function get (url, params, config) {
if (config) {
axios.defaults.headers.post['Content-Type'] = 'multipart/form-data'
}
// LoadingBar.start()
let phpApi = false
// get方法中使用php接口地址
if (
url === '/index.php/file/upload_token' ||
url === '/index.php/home_page/currency' ||
url === '/index.php/count_channel/channel_province_count' ||
url === '/index.php/count_channel/channel_history_count' ||
url === '/index.php/count_channel/channel_role_count' ||
url === '/index.php/count_channel/channel_newadd_count' ||
url === '/index.php/count_project/project_num_count' ||
url === '/index.php/count_project/department_count' ||
url === '/index.php/count_project/project_count_total' ||
url === '/index.php/user/department' ||
url === '/index.php/count_project/project_department_num_count' ||
url === '/index.php/count_project/province_count' ||
url === '/index.php/count_project/clue_source_count' ||
url === '/index.php/count_project/stage_count' ||
url === '/index.php/count_project/reason_count' ||
url === '/index.php/count_project/project_time_count' ||
url === '/index.php/count_project/project_time_department_count' ||
url === '/index.php/count_project/duban_money_count' ||
url === '/index.php/count_project/refuse_count' ||
url === '/index.php/count_project/project_evaltime_count' ||
url === '/index.php/count_project/accept_count'
) {
phpApi = true
} else {
phpApi = false
}
// 线上环境
if (process.env.NODE_ENV === 'production') {
// 上传token
if (phpApi) {
axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
} else {
axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
}
} else {
// 开发测试环境
// 获取上传token
if (phpApi) {
axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
} else {
axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
}
}
return new Promise(async (resolve, reject) => {
await axios.get(url, {
params: params,
cancelToken: new CancelToken(c => {
cancel = c
})
}).then(res => {
resolve(res.data)
// LoadingBar.finish()
}).catch(err => {
reject(err.data)
// LoadingBar.error()
})
})
}
export function post (url, params, config) {
if (config) {
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
}
// LoadingBar.start()
console.log(window.location.hash)
return new Promise((resolve, reject) => {
// 线上环境
if (process.env.NODE_ENV === 'production') {
// php接口
if (
url === '/index.php/login/account' ||
url === '/index.php/login/wechat' ||
url === '/index.php/login/un_login'
) {
axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
} else if (url === 'qiniu') {
axios.defaults.baseURL = ''
url = 'https://qiniu.pangu.tech/'
} else {
// java接口
axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
}
} else {
// 开发测试环境
// 如果是php接口
if (
url === '/index.php/login/account' ||
url === '/index.php/login/wechat' ||
url === '/index.php/login/un_login'
) {
axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
} else if (url === 'qiniu') {
axios.defaults.baseURL = ''
url = 'https://qiniu.pangu.tech/'
} else {
// java接口
axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
}
}
axios.post(
url,
params,
{
cancelToken: new CancelToken(c => {
cancel = c
})
}
).then(res => {
resolve(res.data)
// LoadingBar.finish()
}).catch(err => {
reject(err.data)
// LoadingBar.error()
})
})
}
export function put (url, params) {
// LoadingBar.start()
console.log(window.location.hash)
return new Promise((resolve, reject) => {
// 线上环境
if (process.env.NODE_ENV === 'production') {
if (
url === '/index.php/login/account' ||
url === '/index.php/project/up_status'
) {
axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
} else if (url === 'qiniu') {
axios.defaults.baseURL = ''
url = 'https://qiniu.pangu.tech/'
} else {
axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
}
} else {
// 开发测试环境
if (
url === '/index.php/login/account' ||
url === '/index.php/project/up_status'
) {
axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
} else {
axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
}
}
axios.put(
url,
params,
{
cancelToken: new CancelToken(c => {
cancel = c
})
}
).then(res => {
resolve(res.data)
// LoadingBar.finish()
}).catch(err => {
reject(err.data)
// LoadingBar.error()
})
})
}
export function getAxios () {
// 线上环境
if (process.env.NODE_ENV === 'production') {
axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
} else {
// 开发测试环境
axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
}
return axios
}
实践证明这样封装是有问题的
下面展示真正的技术
// 引入axios
import axios from 'axios'
...
// 声明一个数组用于存储每个请求的取消函数和axios标识
let pending = []
const CancelToken = axios.CancelToken
let removePending = (config) => {
for (let p in pending) {
if (pending[p].u === config.url + JSON.stringify(config.data) + '&' + config.method) {
pending[p].f()
pending.splice(p, 1)
}
}
}
...
// 请求拦截器
axios.interceptors.request.use(config => {
// 取消请求
removePending(config)
config.cancelToken = new CancelToken((c) => {
// 这里的axios标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
pending.push({ u: config.url + JSON.stringify(config.data) + '&' + config.method, f: c })
})
...
})
...
// 响应拦截器
axios.interceptors.response.use(response => {
...
// 取消响应
removePending(response.config)
...
})
这样在请求和响应中拦截就可以了