Axios 是什么
Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。
Axios 优点
Axios 有诸多优点。在详细用法部分,我将结合例子分别讲解
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
详细用法
先用 Koa web 框架搭建一个简单的 http 服务器,提供 API 供 axios 使用。
js
const Koa = require("koa");
const app = new Koa();
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const router = new Router();
const cors = require("koa-cors");
app.use(bodyParser());
app.use(
cors({
credentials: true,
})
);
router.get("/person", (ctx) => {
// const { name, age } = ctx.query;
ctx.body = {
name: "qin",
age: 25,
};
});
router.post("/book", (ctx) => {
const { title, price, ...rest } = ctx.request.body;
ctx.body = {
title,
price,
...rest,
};
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3002, () => {
console.log("server is running at port 3002");
});
app.on("error", (err) => {
console.error(err);
});
接下来,分别分析 Axios 的功能点。
- 从浏览器中创建 XMLHttpRequests
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Axios</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
// 创建 get 请求
axios
.get("http://localhost:3002/person")
.then(function (res) {
console.log(res.data); // { name: 'qin', age: 25 }
})
.catch(function (error) {
console.log(error);
});
// 创建 post 请求
axios
.post("http://localhost:3002/book", {
title: "JavaScript高级程序设计",
price: 99,
})
.then(function (res) {
console.log(res.data); // { title: "JavaScript高级程序设计", price: 99 }
})
.catch(function (error) {
console.log(error);
});
</script>
</body>
</html>
- 从 node.js 创建 http 请求
js
// index.js
const axios = require("axios");
// 创建 get 请求
axios
.get("http://localhost:3002/person")
.then(function (res) {
console.log(res.data); // { name: 'qin', age: 25 }
})
.catch(function (error) {
console.log(error);
});
// 创建 post 请求
axios
.post("http://localhost:3002/book", {
title: "JavaScript高级程序设计",
price: 99,
})
.then(function (res) {
console.log(res.data); // { title: "JavaScript高级程序设计", price: 99 }
})
.catch(function (error) {
console.log(error);
});
然后在终端执行 node index.js
。会依次看到 console.log 方法打印出结果。
js
{ name: 'qin', age: 25 }
{ title: "JavaScript高级程序设计", price: 99 }
- 支持 Promise API
Axios 支持 Promise API,也就是说支持 axios.get(url).then().catch()
和 async/await
使用形式。请看下面的例子。
js
// index.js
const axios = require("axios");
// 用法1
axios
.get("http://localhost:3002/person")
.then((res) => console.log(res.data)) // { name:"qin", age: 25 }
.catch((err) => console.log(err));
然后在终端执行 node index.js
。会看到
js
console.log(result.data); // { name:"qin", age: 25 }
- 拦截请求和响应
在请求或响应被 then 或 catch 处理前拦截它们。下面,在 Node.js 环境里,给出拦截请求和响应的例子。
js
// index.js
const axios = require("axios");
// 添加请求拦截器
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);
}
);
- 转换请求数据和响应数据
转换请求数据 发送请求前,对传入的数据进行修改。转换响应数据 接收响应后,对接收的数据进行修改。主要是下面两个属性。
js
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
在 Node.js 环境下,来看看 transformRequest
和 transformResponse
使用例子。
js
// index.js
const axios = require("axios");
const { omit } = require("lodash");
axios
.post(
"http://localhost:3002/book",
{
title: "JavaScript高级程序设计",
price: 99,
},
{
transformRequest: [
function (data) {
data.author = "尼古拉斯·泽卡斯";
return data;
},
...axios.defaults.transformRequest,
],
transformResponse: [
function (data) {
return omit(JSON.parse(data), "price");
},
...axios.defaults.transformResponse,
],
}
)
.then((res) => console.log(res.data)) // { title: "JavaScript高级程序设计", author: "尼古拉斯·泽卡斯" }
.catch((err) => console.error(err));
- 取消请求
使用 cancel token 取消请求
Axios 的 cancel token API 基于 cancelable promises proposal,它还处于第一阶段。
可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:
js
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios
.get("/user/12345", {
cancelToken: source.token,
})
.catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log("Request canceled", thrown.message);
} else {
// 处理错误
}
});
// 取消请求(message 参数是可选的)
source.cancel("Operation canceled by the user.");
还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
js
var CancelToken = axios.CancelToken;
var cancel;
axios.get("/user/12345", {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
}),
});
**在前端通过 Ajax 做大文件断点续传的场景下,会使用到取消请求功能。**
// 取消请求
cancel();
Note: 可以使用同一个 cancel token 取消多个请求
- 自动转换 JSON 数据
axios 通过设置 transformResponse,可自动转换请求返回的 JSON 数据。详情请看 axios/axios/blob/master/lib/defaults.js 部分源码。
js
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */ }
}
return data;
}],
- 客户端支持防御 XSRF
先来了解一下 XSRF,以下内容来自维基百科。
XSRF 跨站请求伪造(Cross-site request forgery),是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。
举个例子:
假如一家网站执行转账的操作 URL 地址如下:
www.examplebank.com/withdraw?ac...
那么,一个恶意攻击者可以在另一个网站上放置如下代码:
<img src="www.examplebank.com/withdraw?ac...
如果有账户名为 Alice 的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失 1000 资金。
-------我是分割线,以上内容来自维基百科-------
那么 Axios 怎么防御 XSRF 攻击呢
js
// 添加 xsrf 请求头
// 只在标准浏览器环境中才会起作用
if (utils.isStandardBrowserEnv()) {
var cookies = require("./../helpers/cookies");
}
// 添加 xsrf 请求头
var xsrfValue =
(config.withCredentials || isURLSameOrigin(config.url)) && config.xsrfCookieName
? cookies.read(config.xsrfCookieName)
: undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
下面来看看这个例子。
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Axios</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
axios
.post(
"http://localhost:3002/book",
{
title: "JavaScript高级程序设计",
price: 99,
},
{
withCredentials: true,
}
)
.then(function (res) {
console.log(res.data); // { title: "JavaScript高级程序设计", price: 99 }
})
.catch(function (error) {
console.log(error);
});
</script>
</body>
</html>
首先,axios 会检查是否是标准的浏览器环境,然后在标准的浏览器环境中判断,如果设置了跨域请求时需要凭证且请求的域名和页面的域名相同时,读取 cookie 中 xsrf token 的值,并设置到承载 xsrf token 的值的 HTTP 请求头中。