Promise based HTTP client for the browser and node.js
這是 Axios 的定義,Axios 是基於 Promise,用於HTTP客戶端——瀏覽器和 node.js 的庫 。Github:https://github.com/mzabriskie/axios。node
官方文檔中 Axios 的 feature 有:react
1)瀏覽器中使用 XMLHttpRequest;ios
2)node.js 中使用 http 請求;git
3)支持 Promise API;github
4)可以攔截請求與響應;web
5)可以轉換請求與響應的數據;面試
6)請求可以取消;json
7)自動轉換 JSON 數據;axios
8)客戶端支持防範 XSRF;react-native
記得有一次面試中,面試官問到,Axios 是用什麼實現的,我回答說 Ajax。看面試官的表情,他彷佛認爲這個答案是錯的。後來仔細想了一下,Axios 是用 Ajax 實現異步請求的, 而異步操做則是基於 Promise 的。而 Axios 的目的呢,就是爲了在瀏覽器和 node.js 中,以統1、簡潔的方式使用 Ajax、處理回調。簡單的說,就是用 Promise 包裝了一下 AJAX(固然並無這麼簡單)。
最簡單的使用方法,僅僅須要向 Axios 傳遞請求地址,即可以發送一個 GET 請求。Ajax 中其它的配置 Axios 都已經默認設置好了。固然也能夠根據需求傳入 config,覆蓋默認配置項。默認配置定義在 /lib/defaults.js 中。
axios(url[, config])
var defaults = { adapter: getDefaultAdapter(), transformRequest: [...], transformResponse: [...], timeout: 0, // 請求超時時間 xsrfCookieName: 'XSRF-TOKEN', // 用於獲取 cookie 中 'XSRF-TOKEN' 的值 xsrfHeaderName: 'X-XSRF-TOKEN', // 用於設置請求頭部 maxContentLength: -1, validateStatus: function validateStatus(status) { return status >= 200 && status < 300; } }; defaults.headers = { common: { 'Accept': 'application/json, text/plain, */*' } }; utils.forEach(['delete', 'get', 'head'], function forEachMehtodNoData(method) { defaults.headers[method] = {}; }); utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE); }); module.exports = defaults;
瀏覽器和 node.js 實現異步請求的方式並不同,那麼 Axios 如何實現統一呢?
function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== 'undefined') { // For browsers use XHR adapter adapter = require('./adapters/xhr'); } else if (typeof process !== 'undefined') { // For node use HTTP adapter adapter = require('./adapters/http'); } return adapter; }
var defaults = {
adapter: getDefaultAdapter(),
...
}
module.exports = defaults;
在 defaults.js 中,經過分支選擇判斷,若 XMLHttpRequest 存在,表明當前環境爲瀏覽器, 則異步請求將使用 XHR;不然,若存在 process,表明當前環境爲 node.js,則使用 HTTP。
Axios 基於 Promise 就體如今 adapter。不管是 XHR 仍是 HTTP,都是通過 Promise 包裝的,getDefaultAdapter() 返回的都是一個 Promise 對象。若是但願使用 fetch 或者其餘自定義,在 config 中傳入 adapter 就能夠了,參考 gthub 的 /lib/adapters/README.md 的示例, adapter 應該是一個 Promise 對象。
在瀏覽器中 Axios 使用的是 XMLHttpRequest。咱們一般會將 Ajax 等同於 XMLHttpRequest,但二者並不同。《JavaScript 高級程序設計》中提到,「Ajax 技術的核心是 XMLHttpRequest 對象(簡稱XHR)」。在 xhr.js 中,主要是對 XHR請求以及響應數據的一些封裝,使它可以兼容 IE8/9。
上文提到客戶端支持 XSRF防範 ,是在 xhr.js 中實現。往請求頭中插入‘X-XSRF-TOKEN’字段。
// Add xsrf header // This is only done if running in a standard browser environment. // Specifically not if we're in a web worker, or react-native. if (utils.isStandardBrowserEnv()) { var cookies = require('./../helpers/cookies'); // Add xsrf header var xsrfValue = (config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName ? cookies.read(config.xsrfCookieName) : undefined; if (xsrfValue) {
// 默認配置中 xsrfHeadeName: 'X-XSRF-TOKEN' requestHeaders[config.xsrfHeaderName] = xsrfValue; } }
transformRequest 是根據請求數據的類型對數據進行轉換,並改變 Content-Type。默認的 Content-Type 爲 ‘application/x-www-form-urlencoded’
transformRequest: [function transformRequest(data, headers) { normalizeHeaderName(headers, 'Content-Type'); if (utils.isFormData(data) || utils.isArrayBuffer(data) || utils.isStream(data) || utils.isFile(data) || utils.isBlob(data) ) { return data; } if (utils.isArrayBufferView(data)) { return data.buffer; } if (utils.isURLSearchParams(data)) { setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8'); return data.toString(); } if (utils.isObject(data)) { setContentTypeIfUnset(headers, 'application/json;charset=utf-8'); return JSON.stringify(data); } return data; }],
transformResponse
transformResponse 默認將響應數據轉換爲 JSON格式。
transformResponse: [function transformResponse(data) { /*eslint no-param-reassign:0*/ if (typeof data === 'string') {
// var PROTECTION_PREFIX = /^\)\]\}',?\n/; data = data.replace(PROTECTION_PREFIX, ''); try { data = JSON.parse(data); } catch (e) { /* Ignore */ } } return data; }],
瞭解 Axios 的默認配置項以後,就明白如何經過 config 來自定義請求了。