axios面試常問題目及其詳解
以下是前端面試中關于 Axios 的常見問題及詳細解答,涵蓋核心原理、實戰場景和進階優化,幫助你在面試中清晰展示技術深度。
1. Axios 是什么?它與原生 Fetch API 有何區別?
回答要點:
- Axios 是什么:
Axios 是一個基于 Promise 的 HTTP 客戶端,用于瀏覽器和 Node.js 環境。它封裝了底層的 XMLHttpRequest(瀏覽器)和 http 模塊(Node.js),提供了更簡潔的 API 和豐富的功能(如攔截器、自動轉換 JSON 數據等)。
面試場景:
“在項目中為什么選擇 Axios 而不是 Fetch?”
回答:
“Axios 的攔截器功能可以統一處理認證(如自動附加 Token)、錯誤提示(如 401 跳轉登錄頁)和請求日志,減少重復代碼。此外,Axios 自動轉換 JSON 數據,避免了手動調用 response.json() 的繁瑣操作,尤其在需要兼容 IE 時,Axios 的 Polyfill 支持更友好。”
2. Axios 的攔截器如何工作?實際項目中如何使用?
回答要點:
- 攔截器類型:
- 請求攔截器:在請求發送前執行(如附加 Token、修改請求頭)。
- 響應攔截器:在響應返回后執行(如統一處理錯誤、數據格式化)。
- 代碼示例:
// 請求攔截器:附加 Token
axiosInstance.interceptors.request.use(config => {const token = localStorage.getItem('token');if (token) config.headers.Authorization = `Bearer ${token}`;return config;
});// 響應攔截器:統一處理錯誤
axiosInstance.interceptors.response.use(response => response.data, // 直接返回數據部分error => {if (error.response?.status === 401) {// 跳轉登錄頁window.location.href = '/login';}return Promise.reject(error);}
);
- 實際場景:
- 認證管理:自動附加 Token,避免每個請求手動添加。
- 錯誤兜底:統一處理 4xx/5xx 錯誤,減少組件內的重復代碼。
- 數據格式化:后端返回數據包裹在 { code, data, message } 中,攔截器可提取 data 部分。
面試場景:
“如何通過攔截器實現用戶登錄狀態的自動管理?”
回答:
“在請求攔截器中檢查本地存儲的 Token,并附加到請求頭。在響應攔截器中,如果遇到 401 錯誤(Token 過期),自動清除本地 Token 并跳轉登錄頁,無需在每個 API 調用中重復判斷。”
3. 如何用 Axios 取消重復或過時的請求?
回答要點:
- 取消方式:
- CancelToken(舊版):
const source = axios.CancelToken.source();
axios.get('/api/data', { cancelToken: source.token });
// 取消請求
source.cancel('用戶取消操作');
2. AbortController(推薦):
const controller = new AbortController();
axios.get('/api/data', { signal: controller.signal });
// 取消請求
controller.abort('請求超時');
- 防重復提交:
通過緩存請求標識(如 URL + 參數 + 時間戳),在攔截器中攔截短時間內重復的請求。
示例:
const pendingRequests = new Map();
axiosInstance.interceptors.request.use(config => {const requestKey = `${config.url}-${JSON.stringify(config.params)}`;if (pendingRequests.has(requestKey)) {pendingRequests.get(requestKey).abort(); // 取消前一個相同請求}const controller = new AbortController();config.signal = controller.signal;pendingRequests.set(requestKey, controller);return config;
});
axiosInstance.interceptors.response.use(response => {const requestKey = `${response.config.url}-${JSON.stringify(response.config.params)}`;pendingRequests.delete(requestKey); // 請求完成,移除緩存return response;
});
面試場景:
“用戶快速點擊按鈕多次提交表單,如何避免重復請求?”
回答:
“在請求攔截器中生成請求的唯一標識(如 URL + 參數),并用 Map 緩存正在進行的請求。如果相同請求已存在,則調用 AbortController.abort() 取消前一個請求,確保只有最后一次請求被執行。”
4. Axios 如何處理跨域問題?CORS 和 JSONP 的區別?
回答要點:
-
Axios 跨域解決方案:
- CORS(推薦):后端設置響應頭(如 Access-Control-Allow-Origin),瀏覽器允許跨域請求。
- 簡單請求:直接發送請求。
- 預檢請求(Preflight):先發 OPTIONS 請求,后端需支持 OPTIONS 方法并返回允許的跨域頭。
- 代理服務器:開發時通過 Webpack DevServer 或 Nginx 反向代理,將請求轉發到目標服務器(前端代碼無跨域問題)。
- CORS(推薦):后端設置響應頭(如 Access-Control-Allow-Origin),瀏覽器允許跨域請求。
-
CORS vs JSONP:
|對比項|CORS|JSONP|
|原理|基于 HTTP 頭部的跨域控制|利用
面試場景:
“項目遇到跨域問題,如何通過 Axios 解決?”
回答:
“如果是開發環境,通過 Webpack DevServer 配置代理,將 API 請求轉發到后端服務器。生產環境則讓后端配置 CORS 頭,允許前端域名訪問。JSONP 僅作為備選方案,因僅支持 GET 且安全性較低。”
5. 如何實現 Axios 的請求重試機制?
回答要點:
- 實現思路:
在響應攔截器中捕獲網絡錯誤或特定狀態碼(如 5xx),通過遞歸或定時器重試請求。
代碼示例:
axiosInstance.interceptors.response.use(null, error => {if (error.code === 'ECONNABORTED' || !error.response) {// 網絡超時或斷開,重試return retryRequest(error.config);}return Promise.reject(error);
});function retryRequest(config, retryCount = 3) {if (retryCount <= 0) return Promise.reject('重試次數耗盡');config.__retryCount = config.__retryCount || 0;config.__retryCount += 1;return new Promise(resolve => {setTimeout(() => {resolve(axiosInstance(config));}, 1000 * config.__retryCount); // 指數退避}).then(response => response).catch(err => retryRequest(config, retryCount - 1));
}
- 適用場景:
- 網絡不穩定導致請求失敗。
- 后端服務臨時不可用(如 502/504 錯誤)。
面試場景:
“如何優化弱網環境下的請求成功率?”
回答:
“通過攔截器實現請求重試機制
,結合指數退避策略(如首次重試延遲 1s,第二次 2s)
,避免短時間內頻繁重試加重服務器負擔。同時限制最大重試次數(如 3 次),防止無限重試
。”
6. Axios 的全局配置和實例化配置有何區別?
回答要點:
- 全局默認配置:
通過axios.defaults
設置,影響所有請求(不推薦,易產生沖突)。
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
- 實例化配置:
創建獨立的 Axios 實例,每個實例可單獨配置,避免全局污染。
const apiInstance = axios.create({baseURL: 'https://api.example.com',timeout: 5000,
});
apiInstance.interceptors.request.use(...); // 實例級攔截器
- 優先級:
實例配置 > 全局配置 > 請求配置
(axios.get(url, { timeout: 10000 }) 可覆蓋實例配置)。
面試場景:
“多個模塊需要調用不同后端 API,如何管理 Axios 配置?”
回答:
“為每個模塊創建獨立的 Axios 實例,分別配置 baseURL 和攔截器。例如,用戶模塊實例指向 /user 接口,支付模塊實例指向 /pay 接口,避免全局配置混亂。”
總結
在面試中回答 Axios 相關問題時,需結合 原理、實戰場景 和 代碼實現,突出以下能力:
- 對
底層機制
的理解(如攔截器、取消請求)。 - 解決
實際問題
的經驗(如跨域、重復提交、錯誤處理)。 - 代碼
設計的規范性
(如實例化配置、重試機制)。
通過清晰的邏輯和具體的例子,可以充分展示你對 Axios 的掌握程度和工程化思維。
下面是一些關于 Axios
在前端面試中常見的問題及其詳解,涵蓋了基礎用法、配置、攔截器、錯誤處理等方面,適合前端開發崗位:
? 基本 Axios 面試題目詳解
1. 什么是 Axios?它有哪些特點?
答案:
Axios 是一個基于 Promise 的 HTTP 客戶端,用于瀏覽器和 Node.js。
特點:
- 支持 Promise API
- 支持請求/響應攔截器
- 請求和響應數據轉換
- 自動轉換 JSON 數據
- 防止 CSRF/XSRF 攻擊
- 客戶端支持取消請求(通過 CancelToken)
- 支持并發請求(
axios.all()
)
2. Axios 和 Fetch 的區別?
特點 | Axios | Fetch |
---|---|---|
默認數據格式 | JSON 自動解析 | 需要手動解析 .json() |
請求攔截器 | 支持 | 不支持 |
響應攔截器 | 支持 | 不支持 |
超時設置 | 支持 | 需手動實現 |
請求取消 | 支持 CancelToken | 需使用 AbortController |
瀏覽器兼容性 | 更好 | 較新瀏覽器支持更好 |
3. 如何配置全局默認值?
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
axios.defaults.headers.common['Authorization'] = 'Bearer token';
4. Axios 如何設置請求攔截器和響應攔截器?
// 請求攔截器
axios.interceptors.request.use(config => {// 可添加 token 等操作config.headers['X-Custom-Header'] = 'value';return config;
}, error => Promise.reject(error));// 響應攔截器
axios.interceptors.response.use(response => {return response.data; // 直接返回數據部分
}, error => {// 錯誤處理if (error.response) {// 服務端返回錯誤console.error('Error:', error.response.status);} else if (error.request) {// 沒有響應console.error('No response received');} else {console.error('Request setup error:', error.message);}return Promise.reject(error);
});
5. Axios 如何發送 GET、POST 請求?
// GET 請求
axios.get('/user', { params: { id: 1 } });// POST 請求
axios.post('/user', { name: 'John', age: 25 });
6. 如何處理請求錯誤?
axios.get('/user/123').then(response => console.log(response)).catch(error => {if (error.response) {console.log('Status:', error.response.status);console.log('Data:', error.response.data);} else if (error.request) {console.log('No response:', error.request);} else {console.log('Error:', error.message);}});
7. 如何取消 Axios 請求?
const CancelToken = axios.CancelToken;
const source = CancelToken.source();axios.get('/user', {cancelToken: source.token
}).catch(thrown => {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);}
});source.cancel('Request canceled by user');
8. 如何使用 Axios 并發請求?
axios.all([axios.get('/user'),axios.get('/profile')
]).then(axios.spread((userRes, profileRes) => {console.log(userRes.data);console.log(profileRes.data);
}));
9. Axios 如何上傳文件?
const formData = new FormData();
formData.append('file', fileInput.files[0]);axios.post('/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' }
});
10. 如何在 Axios 中設置超時時間?
axios.get('/slow-api', {timeout: 3000 // 毫秒
});
? 高階 Axios 面試題目詳解
1. Axios 請求流程底層是如何工作的?
回答要點:
Axios 封裝了 XMLHttpRequest(瀏覽器端)或 http 模塊(Node.js),主要流程如下:
- 創建 Axios 實例(配置合并)。
- 執行請求攔截器(通過攔截器鏈)。
- 發起請求(瀏覽器中通過
XMLHttpRequest
)。 - 接收響應并執行響應攔截器。
- 返回 Promise。
底層通過一個責任鏈模式(InterceptorManager)來組織攔截器,實際調用棧如下:
dispatchRequest(config) -> xhrAdapter(config) -> new XMLHttpRequest
2. Axios 攔截器是如何實現的?是同步還是異步?
回答要點:
-
攔截器是通過攔截器鏈(interceptors)維護的:
axios.interceptors.request.use(fn1); axios.interceptors.response.use(fn2);
-
這些攔截器會被組成一個
Promise chain
鏈式結構:
let chain = [dispatchRequest, undefined]; // 核心請求處理
// 前置攔截器從前往后插入
// 后置攔截器從后往前插入// 然后通過 promise 鏈式調用處理請求
- 所以攔截器是異步可控的 Promise 鏈調用機制。
3. Axios 如何實現請求合并或去重(防止重復請求)?
回答要點:
可通過維護一個請求隊列 Map 實現唯一 key:
const pendingMap = new Map();function generateKey(config) {const { url, method, params, data } = config;return `${method}&${url}&${JSON.stringify(params)}&${JSON.stringify(data)}`;
}function addPending(config) {const key = generateKey(config);if (!pendingMap.has(key)) {config.cancelToken = new axios.CancelToken(cancel => {pendingMap.set(key, cancel);});} else {// 取消已有重復請求pendingMap.get(key)();}
}
4. 如何封裝 Axios 支持自動刷新 token(如 401 自動重發)?
回答要點:
- 在響應攔截器中捕獲 401。
- 發起
refreshToken
請求(需要排隊等待)。 - 更新 token 后重放之前失敗的請求。
關鍵代碼片段:
let isRefreshing = false;
let failedQueue = [];axios.interceptors.response.use(res => res,async error => {const originalRequest = error.config;if (error.response.status === 401 && !originalRequest._retry) {if (!isRefreshing) {isRefreshing = true;const newToken = await refreshToken();axios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;failedQueue.forEach(cb => cb(newToken));failedQueue = [];isRefreshing = false;}return new Promise(resolve => {failedQueue.push(token => {originalRequest.headers['Authorization'] = 'Bearer ' + token;resolve(axios(originalRequest));});});}return Promise.reject(error);}
);
5. Axios 在 Node.js 和瀏覽器中有何差異?
特性 | 瀏覽器端 | Node.js |
---|---|---|
請求模塊 | XMLHttpRequest | http / https |
Cookie | 自動攜帶 | 需手動配置 |
XSRF | 有默認支持 | 需自己配置 |
適配器 | xhrAdapter | httpAdapter |
Axios 使用的是 adapter 模式:defaultAdapter
會根據運行環境自動選擇。
6. 如何在 Axios 中實現重試機制?
回答要點:
可以通過封裝請求邏輯或使用攔截器實現簡單重試邏輯:
axios.interceptors.response.use(null, async error => {const config = error.config;if (!config || config.__retryCount >= 3) return Promise.reject(error);config.__retryCount = config.__retryCount || 0;config.__retryCount += 1;// 延遲重試await new Promise(res => setTimeout(res, 1000));return axios(config);
});
7. Axios 源碼中的 InterceptorManager
是怎么工作的?
回答要點:
它維護了一個攔截器隊列(handlers 數組),每個元素都有:
{fulfilled: Function,rejected: Function
}
當執行請求時,會將所有攔截器依次插入 Promise 鏈中:
let chain = [...requestInterceptors, dispatchRequest, ...responseInterceptors];
通過 Promise.resolve(config).then(...)
順序執行所有攔截器。
8. Axios 如何實現適配器 Adapter 機制?
回答要點:
const adapter = config.adapter || defaultAdapter;
return adapter(config).then(...)
Axios 默認支持兩種 adapter:
xhrAdapter
:瀏覽器端用XMLHttpRequest
httpAdapter
:Node.js 用http.request
適配器允許我們定制不同平臺下的請求方式,非常靈活。
9. Axios 如何防止 CSRF 攻擊?
回答要點:
Axios 支持自動攜帶 CSRF Token:
axios.defaults.xsrfCookieName = 'XSRF-TOKEN';
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';
如果服務端通過 Cookie 設置了 XSRF-TOKEN
,Axios 會自動讀取并在請求頭加上 X-XSRF-TOKEN
。
10. Axios 是如何合并配置項的?為什么有些配置全局無法覆蓋?
回答要點:
Axios 使用 utils.mergeConfig()
深度合并默認配置和實例配置,其中:
- 一些字段采用深合并(如
headers
) - 一些字段直接覆蓋(如
url
,timeout
)
源碼中的合并策略控制了不同字段的合并行為,導致有時 axios.defaults
無法覆蓋實例設置。