“Did the API request fail? There was no prompt at all!” “The backend returned 401, and Iām still clicking on the page…”
If you have encountered similar awkward situations in your project, you may need to understand the HTTP request interception and error handling mechanism in the frontend.
In modern frontend projects like Vue/React, API requests are at the core of daily development. How to elegantly manage these requests globally ā including adding tokens uniformly, displaying error pop-ups, automatically redirecting to login, and capturing network exceptions ā is crucial for the robustness of the project.
This article will explain how to <span><span>axios</span></span> can be used to intercept requests and responses, centrally handle exceptions, and enhance user experience and development efficiency.
š¦ What are Request Interception and Response Interception?
When using <span><span>axios</span></span>, interceptors can be used to uniformly add or process each request/response, similar to applying middleware to the API.
// Request interceptor
axios.interceptors.request.use(config => {
// Add token before sending the request
config.headers.Authorization = getToken();
return config;
}, error => Promise.reject(error));
// Response interceptor
axios.interceptors.response.use(response => {
// Preprocess successful response data
return response.data;
}, error => {
// Unified error handling
handleError(error);
return Promise.reject(error);
});
⨠Request Interception: Unified Handling of Pre-Request Operations
Request interception is typically used for:
| Purpose | Example |
|---|---|
| Adding authentication token | Include <span><span>Authorization</span></span> request header |
| Adding a unified prefix or baseUrl | Adapting to proxies or environments |
| Initiating loading state | Displaying page loading animation |
| Including traceId / sessionId | Backend log positioning, process tracking |
Example code:
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
// Other headers can be added
config.headers['X-Request-Id'] = generateUUID();
return config;
}, error => {
return Promise.reject(error);
});
ā Response Interception: Unified Handling of Return Results and Errors
Response interception can perform two tasks:
ā 1. Unified Data Format Handling
Many APIs return formats like:
{"code":0,"data":{...},"msg":"Success"}
This can be uniformly processed as:
axios.interceptors.response.use(response => {
const { code, data, msg } = response.data;
if (code === 0) {
return data;
} else {
ElMessage.error(msg || 'Request failed');
return Promise.reject(new Error(msg));
}
});
Thus, components can directly use:
const res = await api.getUser(); // Returns data
ā 2. Error Handling (401, 500, Network Disconnection, etc.)
axios.interceptors.response.use(
res => res,
error => {
const status = error.response?.status;
if (status === 401) {
ElMessage.warning('Login has expired, please log in again');
router.push('/login');
} else if (status === 500) {
ElMessage.error('The server is having issues, please try again later');
} else if (!error.response) {
ElMessage.error('Network exception, please check your network connection');
} else {
ElMessage.error(error.response.data?.msg || 'Request failed');
}
return Promise.reject(error);
}
);
š Recommended Strategies for Practical Implementation
In actual projects, we recommend organizing HTTP interception and error handling logic as follows:
ā Modularized Interceptor Registration
// http.ts
import axios from 'axios';
import { ElMessage } from 'element-plus';
const instance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
});
// Request interceptor
instance.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) config.headers['Authorization'] = `Bearer ${token}`;
return config;
});
// Response interceptor
instance.interceptors.response.use(
res => {
const { code, data, msg } = res.data;
if (code === 0) return data;
ElMessage.error(msg || 'Request failed');
return Promise.reject(new Error(msg));
},
error => {
const status = error.response?.status;
if (status === 401) {
ElMessage.warning('Login expired, please log in again');
location.href = '/login';
} else {
ElMessage.error('Network error or service exception');
}
return Promise.reject(error);
}
);
export default instance;
ā API Call Example
// api/user.ts
import request from '@/utils/http';
export function getUserInfo() {
return request.get('/user/info');
}
š Common Error Scenario Handling Suggestions
| Error Type | Recommended Action |
|---|---|
| 401 Unauthorized | Clear token, redirect to login page |
| 403 Insufficient Permissions | Show prompt, no redirection |
| 404 API Not Found | Prompt and report error log |
| 500 Backend Exception | Popup prompt, allow user to retry |
| Network Timeout / Disconnection | Prompt network issues, optional loading fallback |
| code !== 0 | Prompt user according to backend-defined rules |
šÆ Summary
- ā Use request interceptors to uniformly add tokens and traceIds;
- ā Use response interceptors to uniformly handle code checks and exception prompts;
- ā Error handling should be clear and provide feedback, avoiding “black box usage” for users;
- ā It is recommended to modularize interceptor logic to avoid duplicate code;
- ā The larger the project, the more significant the benefits of unified error handling.
You can further introduce:
- š
<span><span>Sentry</span></span>and other error monitoring tools to log exceptions - ā± Unified handling of loading states (e.g., in conjunction with a global loading manager)
- š„ Request cancellation features (e.g., interrupting unnecessary requests during route changes)
How do you handle HTTP requests and errors in your project? Feel free to share your experiences in the comments!