TypeScript 简单封装 axios

初始化

1
2
3
4
5
create-react-app project-axios --typescript
cd project-axios
yarn add axios @types/axios qs @types/qs parse-headers
yarn add express body-parser
yarn start

删除 src/ 下的内容,新建 index.tsx
新建 src/api.js 作为后台接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
let express = require('express');
let bodyParser = require('body-parser');
let app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(function (req, res, next) {
res.set({
'Access-Control-Allow-Origin': 'http://localhost:3000',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'GET,POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type,name'
});
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
app.get('/get', function (req, res) {
res.json(req.query);
});
app.post('/post', function (req, res) {
res.json(req.body);
});
app.post('/post_timeout', function (req, res) {
let { timeout } = req.query;
console.log(req.query);

if (timeout) {
timeout = parseInt(timeout);
} else {
timeout = 0;
}
setTimeout(function () {
res.json(req.body);
}, timeout);
});
app.post('/post_status', function (req, res) {
let { code } = req.query;
if (code) {
code = parseInt(code);
} else {
code = 200;
}
res.statusCode = code;
res.json(req.body);
});
app.listen(8080);

运行后台接口程序 nodemon api.js

访问: http://localhost:8080/get?name=jiafei&age=18 浏览器返回 {“name”:”jiafei”,”age”:”18”}

开始

get请求

src/index.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import axios, { AxiosResponse} from 'axios';
const BaseUrl = "http://localhost:8080";
// 它指的是服务器返回的对象
interface User{
name: string,
password: string
}
let user:User = {
name: 'jiafei',
password: '123456'
}
axios({
method: 'get',
url: BaseUrl + '/get',
params: user //查询参数对象,它会转成查询字符串放在?的后面
}).then((response: AxiosResponse) => {
console.log(response);
return response.data;
}).catch((error: any) => {
console.log(error);
})

运行:yarn start
访问:http://localhost:3000/get?name=jiafei&password=123

查看源码

github 搜索 axios
点开 index.js module.exports = require(‘./lib/axios’);
找到 /lib/axios.js 它上面创建实例的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);

// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);

// Copy context to instance
utils.extend(instance, context);

return instance;
}

手写axios

新建 /lib/index.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
import Axios from './Axios';
//可以创建一个axios的实例 axios其实就是一个函数
//定义一个类的时候,一个类的原型 ,Axios.prototype 一个是类的实例, 如line6 一个类的实例的类型就是这个类本身(Axios)
function createInstance() {
let context: Axios = new Axios();//this指针上下文
//让request 方法里的this永远指向context也就是new Axios()
let instance = Axios.prototype.request.bind(context);
//把Axios的类的实例和类的原型上的方法都拷贝到了instance上,也就是request方法上
instance = Object.assign(instance, Axios.prototype, context);
return instance;
}
let axios = createInstance();
export default axios;

新建 /lib/axios.tsx

1
2
3
4
export default class Axios {
request(){
}
}

新建 /lib/types.tsx

1
2
3
4
5
6
7
8
9
10
11
12
export type Methods = 'get' | 'GET' | 'post' | 'POST' | 'put' | 'PUT' | 'delete' | 'DELETE' | 'options' | 'OPTIONS';
export interface AxiosRequestConfig{
url: string,
method: Methods,
params: Record<string,any>
}

// 这里看 src/index.tsx line 12-21 是一个函数config是line12-16的参数列表,返回一个promise
//Promise的泛型T代表此promise变成成功态之后resolve的值 resolve(Value)
export interface AxiosInstance{ // 这个是用来修饰 Axios.prototype.request这个方法
<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>>// 这里Promise要给一个泛型T,*********注意这里是AxiosResponse的T
}

*现在来看 src/index.tsx 中line17 请求的返回参数 * 如下:

这里点击查看 line16 (response: AxiosResponse)中 AxiosResponse
源码如下:

1
2
3
4
5
6
7
8
export interface AxiosResponse<T = any>  {
data: T;
status: number;
statusText: string;
headers: any;
config: AxiosRequestConfig;
request?: any;
}

在我们自己的 /lib/types.tsx中添加如下代码:

1
2
3
4
5
6
7
8
9
// 这个泛型T代表响应体的类型
export interface AxiosResponse<T = any>{
data: T;
status: number;
statusText: string;
headers?: Record<string,any>;
config?: AxiosRequestConfig;
request?: XMLHttpRequest
}