Axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。
Features
- 從瀏覽器中創建 XMLHttpRequests
- 從 node.js 創建 http 請求
- 支持 Promise API
- 攔截請求和響應
- 轉換請求數據和響應數據
- 取消請求
- 自動轉換 JSON 數據
- 客戶端支持防禦 XSRF
axios
有兩種用法。
// 爲給定 ID 的 user 創建請求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 也可以通過 params 對象傳遞參數
axios.get(‘/user’, {
params: {ID: 12345}
}).then(response => {
console.log(response);
}).catch(error => {
console.log(error);
});
// 發送 POST 請求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
}).then(response => {
});
axios
的響應結構
{
// `data` 由服務器提供的響應
data: {},
// `status` 來自服務器響應的 HTTP 狀態碼
status: 200,
// `statusText` 來自服務器響應的 HTTP 狀態信息
statusText: 'OK',
// `headers` 服務器響應的頭
headers: {},
// `config` 是爲請求提供的配置信息
config: {}
}
在實際請求後臺接口時,會要求前端傳入規定格式的數據,比如json
。axios
會在請求之前判斷傳值的類型,並以相應的content-type發送請求到後臺服務器。在這個過程中踩了不少坑,特此,做一個總結。
- 坑1
在使用axios
發送post
請求時,默認的請求頭Content-Type
的屬性值爲application/json
,這個時候瀏覽器會分兩次發送請求,首先使用OPTION方法發送請來詢問服務對請求是否支持,若不支持,則報錯,終止請求的發送。 - 坑2
- 如果用
urlSearchParams
對象傳遞參數,那麼content-type
的值爲application/x-www-form-urlencoded;charset=utf-8
- 如果用
json
對象傳遞參數,那麼content-type
的值爲application/json;charset=utf-8
axios
的源碼
axios.create = function create(instanceConfig) {
return createInstance(utils.merge(defaults, instanceConfig));
};
create
方法就是把我們傳入的參數和默認參數合併,然後創建一個axios
實例,我們再看看defaults
這個配置對象
var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
/* 這個表明默認的Content-Type就是我們想要的 */
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};
/* 看方法名就知道,這個是設置ContentType用的(Content-Type沒有設置的時候) */
function setContentTypeIfUnset(headers, value) {
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = value;
}
}
/* 這個是用來區別對待瀏覽器和nodejs請求發起工具的區別的 */
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(),
/* 這個transformRequest配置就厲害了
* 官方描述`transformRequest` allows changes to the request data before it is sent to the server
* 這個函數是接受我們傳遞的參數,並且在發送到服務器前,可以對其進行更改
* */
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;
}
/* 關鍵點1、如果用URLSearchParams對象傳遞參數,就可以用我們想要的Content-Type傳遞 */
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
/* 關鍵點2、這裏我們看到,如果參數Object的話,就是通過json傳遞 */
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
}],
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */ }
}
return data;
}],
timeout: 0,
xsrfCookieName: '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 forEachMethodNoData(method) {
defaults.headers[method] = {};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
module.exports = defaults;
綜上述,欲傳遞表單數據,則通過urlSearchParams
對象。示例:
import axios from 'axios';
let param = new URLSearchParams();
param.append("username", "admin");
param.append("password", "admin");
axios({
method:'post',
url:'/login',
data:param
}).then(response => { });
- 坑3
當沒有參數傳遞時,設置的content-type
的無用。
axios
源碼如下:
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
// Remove Content-Type if data is undefined
delete requestHeaders[key];
} else {
// Otherwise add header to the request
request.setRequestHeader(key, val);
}
});
}
-
坑4
參考鏈接 -
坑5
this.$axios({
method:'get',
url:'/api/portal/login?loginName='+this.loginName+'&password='+this.password
}).then((response)=>{
console.log(response);
})
這種方式請求頭中content-type
的值爲application/json;charset=UTF-8