Axios拦截器Promise拒绝处理异常:409错误无法传递至组件
Hey there! Let's break down what's going on with your Axios error handling and walk through the right way to fix it.
First, Why Your Original Setup Had Issues
Let's start with the core problem: when you returned Promise.reject(error) from the interceptor, your component's catch block got undefined. The most likely culprit is a typo in your request interceptor's error handler:
// You used `error.message` but the parameter is named `err`! vue.$eventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'});
This throws a ReferenceError (since error isn't defined here), which can override or corrupt the original error object being passed down the chain. That's why your component ended up with undefined instead of the 409 error.
As for why wrapping the error in an object (Promise.reject({error})) worked: you're explicitly packaging the original error into a new object, which avoids the ReferenceError from the typo and ensures something gets passed to the component's catch block. But this is a workaround—let's fix the root issue properly.
How Axios Interceptor Error Handling Works
Axios interceptors rely on Promise chaining to pass errors along. For response interceptors:
- If you return
Promise.reject(error), the error object flows directly to the nextcatchblock in your component. - If you don't return a rejected Promise (e.g., you return a plain value or forget to return anything), Axios will convert the error into a resolved Promise, and your component's
catchwon't trigger at all.
Wrapping the error in an object isn't necessary unless you want to add extra metadata to the error. The cleanest approach is to pass the original error object directly.
Recommended Fix & Implementation
Let's adjust your code step by step:
1. Fix the Request Interceptor Typo
First, correct the reference to the error parameter in the request interceptor:
export function apiFactory(vue, $security) { const $http = axios.create({ baseURL: process.env.API_URL }); $http.interceptors.request.use(function (config) { const token = $security.loginFrame.getToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, function (err) { // Use `err` instead of `error` here vue.$eventBus.$emit('toastMessageHandler', {message: err.message, type: 'error'}); return Promise.reject(err); }); $http.interceptors.response.use(function (response) { return response; }, function (error) { if (error.response && error.response.status === 401) { vue.$eventBus.$emit('authErr', error); } else if (error.response && error.response.status === 403) { alert('you are not authorized, please contact EM support'); } else if (error.response && error.response.status !== 409){ vue.$eventBus.$emit('toastMessageHandler', {message: error.message, type: 'error'}); } // Pass the original error directly to the component's catch block return Promise.reject(error); }); // Don't forget to return the $http instance! return $http; }
2. Clean Up Component Error Handling
Your component code can stay mostly the same, but add safeguards for cases where error.response might not exist (like network errors) and make sure to reset loading state in the catch block:
async addTag() { if (this.newTag.length > 0) { this.loading = true this.$emit('loading', true) const payload = { term: this.newTag, term_type: this.type, partner_code: this.query.partner_code, language: this.query.language } try { await this.apiFacade.createSearchTerm(payload); this.$emit('loading', false) this.loading = false this.tags.unshift(this.newTag) this.newTag = '' this.$eventBus.$emit('toastMessageHandler', { message: this.$t(`search_terms.add_success`), type: 'info' }); } catch (e) { // Use optional chaining to avoid errors if e.response doesn't exist if (e?.response?.status === 409) { this.$eventBus.$emit('toastMessageHandler', { message: this.$t(`search_terms.duplicate_term`), type: 'error' }); } else { // Handle unexpected errors (e.g., network issues) console.error('Unexpected error creating search term:', e); } // Always reset loading state, even if there's an error this.$emit('loading', false) this.loading = false } } }
Extra Tips
- Extend errors if needed: If you want to add custom metadata to errors in the interceptor, modify the original error object instead of wrapping it:
Then access it in the component witherror.customMessage = "Something went wrong with your search term"; return Promise.reject(error);e.customMessage. - Avoid silent failures: Always log unexpected errors in the component's catch block to debug issues quickly.
内容的提问来源于stack exchange,提问作者Michael

