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