# axios概念
- 从浏览器中创建 XMLHttpRequest
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
关于aixos的xsrf防御
Axios 客户端支持防御 XSRF 主要通过在客户端与服务端首次登录确认身份成功后,服务端会颁发给客户端一个身份认证令牌。
客户端往往会把这个 token 添加到请求的 headers 中。
服务器端要求每次请求都包含一个 token,这个 token 是在每次访问站点的时候由服务器端生成的,并通过 set-cookie 的方式种到客户端,然后客户端发送请求的时候,从 cookie 中对应的字段读取出 token,然后添加到请求 headers 中。这样服务端就可以从请求 headers 中读取这个 token 并验证。由于这个 token 是很难伪造的,所以就能区分这个请求是否是用户正常发起的。
axios 在默认请求配置对象中提供了 xsrfCookieName 和 xsrfHeaderName 这两个属性。其中 xsrfCookieName 表示存储 token 的 cookie 的名称,xsrfHeaderName 表示请求 headers 中 token 对应的 header 的名称。然后每次发送请求的时候,会自动从 cookie 中读取对应的 token 值,然后将其添加到请求 headers 中。
xsrfCookieName 和 xsrfHeaderName 这两个属性在axios的配置中默认是没有值的,需要前端自己指定。
一般来说,后端会设置一个cookie,命名为 XSRF-TOKEN,存储XSRF令牌,然后通过HTTP响应头 Set-Cookie 返回给前端。在浏览器中,这个cookie的名字就是 XSRF-TOKEN。
因此,可以在axios的配置中这样设置:
axios.defaults.xsrfCookieName = 'XSRF-TOKEN';
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';
这样,axios在每次发送请求时,都会自动从cookie中获取名为 XSRF-TOKEN 的cookie的值,然后添加到HTTP请求头 X-XSRF-TOKEN 中。
这里只是为了演示如何设置这两个属性,实际的后端配置可能会有所不同。
# 安装
npm install axios
# 执行GET请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
# 执行 POST 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
# 执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
this.$axios.all([
that.$axios.post('/org/findUser1',postData),
that.$axios.post('/org/findUser2',postData)
]).then(that.$axios.spread(function (userResp, userResp2) {
that.inputstr="";
console.log(userResp.data.data.usrList)
// 上面两个请求都完成后,才执行这个回调方法
/*当所有的请求都完成后,会收到一个数组,包含着响应对象,
其中的顺序和请求发送的顺序相同,可以使用 axios.spread 分割成多个单独的响应对象*/
if(userResp.data.meta.success==true){
if(userResp.data.data.usrList){
that.searcharr1=userResp.data.data.usrList;
}else{
that.searcharr1=[];
}
}else{
that.searcharr1=[];
}
if(userResp2.data.meta.success==true){
if(userResp2.data.data.usrList){
that.searcharr2=userResp2.data.data.usrList;
}else{
that.searcharr2=[];
}
}else{
that.searcharr2=[];
}
})).catch(function(err){})
# axios API
可以通过向 axios 传递相关配置来创建请求
axios(config) // 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
axios(url[, config])
// 发送 GET 请求(默认的方法)
axios('/user/12345');
# 请求方法的别名
为方便起见,为所有支持的请求方法提供了别名
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.post(url[, data[, config]])
......
- 注意:在使用别名方法时, url、method、data 这些属性都不必在配置中指定。
# 创建实例
可以使用自定义配置新建一个 axios 实例
axios.create([config])
var instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
# 配置的默认值/defaults
你可以指定将被用在各个请求的配置默认值
# 全局的 axios 默认值
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
# 自定义实例默认值
// 创建实例时设置配置的默认值
var instance = axios.create({
baseURL: 'https://api.example.com'
});
// 在实例已创建后修改默认值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
# 配置的优先顺序
配置会以一个优先顺序进行合并。这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。这里是一个例子:
// 使用由库提供的配置的默认值来创建实例
// 此时超时配置的默认值是 `0`
var instance = axios.create();
// 覆写库的超时默认值
// 现在,在超时前,所有请求都会等待 2.5 秒
instance.defaults.timeout = 2500;
// 为已知需要花费很长时间的请求覆写超时设置
instance.get('/longRequest', {
timeout: 5000
});
# 拦截器
在请求或响应被 then 或 catch 处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
//如果你想在稍后移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义 axios 实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
# 错误处理
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 请求已发出,但服务器响应的状态码不在 2xx 范围内
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
//可以使用 validateStatus 配置选项定义一个自定义 HTTP 状态码的错误范围。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 状态码在大于或等于500时才会 reject
}
})
# axios取消
使用 cancel token 取消请求
Axios 的 cancel token API 基于cancelable promises proposal,它还处于第一阶段。
可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button id="kaishi">开始</button>
<button id="zanting">暂停</button>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
let kaishi=document.getElementById("kaishi")
let zangting=document.getElementById("zanting")
//方案1:通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token
const CancelToken = axios.CancelToken;
let cancel;
kaishi.onclick=function(){
axios.get("http://localhost:9000/ceshi",{
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
}).then(data=>{
console.log(data)
})
}
zanting.onclick=function(){
cancel();
}
//方案2:使用cancelToken.sourse工厂方法创建cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
kaishi.onclick=function(){
axios.get("http://localhost:9000/ceshi",{
cancelToken: source.token
}).then(data=>{
console.log(data)
}).catch(e=>{
console.log(e)
console.log(e.message)//Operation canceled by the user.
})
}
zanting.onclick=function(){
source.cancel('Operation canceled by the user.');
}
</script>
</html>
可以使用同一个 cancel token 取消多个请求,如果请求已经处于传输中,那么取消请求可能会导致请求超时或发生错误。如果服务器已经开始处理请求,那么取消请求可能不会产生任何效果。另外,有些请求可能无法被取消,例如那些没有配置为可取消的请求或者已经完成的请求。
# AbortController
AbortController 接口表示一个控制器对象,允许根据需要中止一个或多个 Web 请求。
可以使用 AbortController() 构造函数创建一个新的 AbortController 对象。使用 AbortSignal 对象可以完成与异步操作的通信。