Javascript Axios/Vue-防止Axios.all()继续执行
在我的应用程序中,我调用fetchData函数对用户进行身份验证。如果用户令牌无效,应用程序将运行Javascript Axios/Vue-防止Axios.all()继续执行,javascript,vue.js,axios,vue-cli,Javascript,Vue.js,Axios,Vue Cli,在我的应用程序中,我调用fetchData函数对用户进行身份验证。如果用户令牌无效,应用程序将运行axios.all(),我的拦截器将返回大量错误 如何防止axios.all()在第一个错误后继续运行?并且只向用户显示一个通知 拦截器.js export default (http, store, router) => { http.interceptors.response.use(response => response, (error) => {
axios.all()
,我的拦截器将返回大量错误
如何防止axios.all()在第一个错误后继续运行?并且只向用户显示一个通知
拦截器.js
export default (http, store, router) => {
http.interceptors.response.use(response => response, (error) => {
const {response} = error;
let message = 'Ops. Algo de errado aconteceu...';
if([401].indexOf(response.status) > -1){
localforage.removeItem('token');
router.push({
name: 'login'
});
Vue.notify({
group: 'panel',
type: 'error',
duration: 5000,
text: response.data.message ? response.data.message : message
});
}
return Promise.reject(error);
})
}
auth.js
const actions = {
fetchData({commit, dispatch}) {
function getChannels() {
return http.get('channels')
}
function getContacts() {
return http.get('conversations')
}
function getEventActions() {
return http.get('events/actions')
}
// 20 more functions calls
axios.all([
getChannels(),
getContacts(),
getEventActions()
]).then(axios.spread(function (channels, contacts, eventActions) {
dispatch('channels/setChannels', channels.data, {root: true})
dispatch('contacts/setContacts', contacts.data, {root: true})
dispatch('events/setActions', eventActions.data, {root: true})
}))
}
}
编辑:更好,因为它允许取消第一次出错后仍挂起的请求,并且不需要任何额外的库。
一种解决方案是为您同时使用的所有请求分配一个唯一标识符(在本例中,我将使用
uuid/v4
包,请随意使用其他内容):
import uuid from 'uuid/v4'
const actions = {
fetchData({commit, dispatch}) {
const config = {
_uuid: uuid()
}
function getChannels() {
return http.get('channels', config)
}
function getContacts() {
return http.get('conversations', config)
}
function getEventActions() {
return http.get('events/actions', config)
}
// 20 more functions calls
axios.all([
getChannels(),
getContacts(),
getEventActions()
]).then(axios.spread(function (channels, contacts, eventActions) {
dispatch('channels/setChannels', channels.data, {root: true})
dispatch('contacts/setContacts', contacts.data, {root: true})
dispatch('events/setActions', eventActions.data, {root: true})
}))
}
}
然后,在拦截器中,您可以选择使用此唯一标识符一次性处理错误:
export default (http, store, router) => {
// Here, you create a variable that memorize all the uuid that have
// already been handled
const handledErrors = {}
http.interceptors.response.use(response => response, (error) => {
// Here, you check if you have already handled the error
if (error.config._uuid && handledErrors[error.config._uuid]) {
return Promise.reject(error)
}
// If the request contains a uuid, you tell
// the handledErrors variable that you handled
// this particular uuid
if (error.config._uuid) {
handledErrors[error.config._uuid] = true
}
// And then you continue on your normal behavior
const {response} = error;
let message = 'Ops. Algo de errado aconteceu...';
if([401].indexOf(response.status) > -1){
localforage.removeItem('token');
router.push({
name: 'login'
});
Vue.notify({
group: 'panel',
type: 'error',
duration: 5000,
text: response.data.message ? response.data.message : message
});
}
return Promise.reject(error);
})
}
另外,您可以将
fetchData
函数简化为:
建议的解决方案需要等待所有响应完成,依赖于uuid
,并在拦截器中增加一些复杂性。我的解决方案避免了所有这些,并实现了终止Promise.all()
执行的目标
Axios支持,因此您可以使用错误处理程序包装GET
请求,该错误处理程序可立即取消其他挂起的请求:
fetchData({ dispatch }) {
const source = axios.CancelToken.source();
// wrapper for GET requests
function get(url) {
return axios.get(url, {
cancelToken: source.token // watch token for cancellation
}).catch(error => {
if (axios.isCancel(error)) {
console.warn(`canceled ${url}, error: ${error.message}`)
} else {
source.cancel(error.message) // mark cancellation for all token watchers
}
})
}
function getChannels() {
return get('https://reqres.in/api/users?page=1&delay=30'); // delayed 30 secs
}
function getContacts() {
return get('https://reqres.in/api/users?page=2'); // no delay
}
function getEventActions() {
return get('https://httpbin.org/status/401'); // 401 - auth error
}
...
}
在拦截器中,您还可以忽略来自请求取消的错误:
export default (http, store, router) => {
http.interceptors.response.use(
response => response,
error => {
if (http.isCancel(error)) {
return Promise.reject(error)
}
...
// show notification here
}
}
作为Axios cancel的替代方案,您可以使用更简单的方法 与旧取消相比,新取消的优点是:
- .cancel()是同步的
- 取消操作无需设置代码
- 与其他蓝鸟功能组合,如Promise.all
promises.forEach(p=>p.cancel())
,以验证在不取消的情况下,无错误调用将一直运行到完成
//对于演示,请检查提取是否完成
const logCompleted=(res)=>console.log(`Promise completed',${res.config.url}`)
函数getChannels(){
返回axios.get(“https://reqres.in/api/users?page=1&delay=5)然后(完成日志)
}
函数getContacts(){
返回axios.get(“https://reqres.in/api/users?page=2)然后(完成日志)
}
函数getEventActions(){
返回axios.get(“https://httpbin.org/status/401)然后(完成日志)
}
Promise.config({cancellation:true});//蓝鸟形态
window.Promise=Promise;//axios承诺现在是蓝鸟口味
常量承诺=[GetChannel()、getContacts()、getEventActions()];
所有(承诺)
。然后(([频道、联系人、事件操作])=>{
log('Promise.all.then',{channels,contacts,eventActions});
})
.catch(错误=>{
log(`Promise.all.catch,${err.message}`)
promises.forEach(p=>p.cancel());
})
.finally(()=>console.log('Promise.all.finally'))
请参见。您也可以用异步生成器
和异步迭代器
替换;另请参见。axio.all()
使用Promise.all()
。您能否演示在第一次异常或被拒绝后继续执行的Promise.all()
?为什么.catch()
没有链接到.then()
来处理错误?axios.all
不执行任何操作,也不能“停止”任何操作。它只是建立了一个等待其他承诺的承诺。您正在立即调用getChannels()
、getContacts()
和getEventActions()
,当您从它们那里得到第一个错误时,它们都已经在运行了。您最好的办法可能是发出一个请求,检查用户令牌是否有效,并且只有在成功后才运行其他令牌。不是依靠拦截器。嗨,我看到你在这个问题上重新开始了悬赏。我的回答怎么没有回答你的问题?你还有其他我的答案不能满足的要求吗?这是我最喜欢的一个,因为它只使用Axios功能,而且正如你在这里所说的,投票结果是等待所有承诺完成。然而,我无法理解如何调用拦截器中第一次失败的通知。是吗?@Hammerbot当取消令牌被调用时,它会对该令牌上所有其他挂起的请求抛出一个错误,这会导致侦听器的错误处理程序被调用。好的,我明白了。该通知之所以显示,是因为第一个错误在第一次取消之前通过了拦截器。这肯定是经过验证的答案。我正在编辑我的答案以提及这一点。
export default (http, store, router) => {
http.interceptors.response.use(
response => response,
error => {
if (http.isCancel(error)) {
return Promise.reject(error)
}
...
// show notification here
}
}