Q Code

遇事不决 可问春风 春风不语 遵循自心

fetch的简单封装

fetch的简单封装

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const TIME_OUT = 6000; // 超时时间
const TOKEN = 'token'; // 自定义token
const ContentType = { // ContentType 映射表
json:'application/json;charset=UTF-8', // json数据格式
form: 'application/x-www-form-urlencoded; charset=UTF-8', // 表单数据格式
download: 'application/octet-stream' // 二进制文件流格式,用于download
};

/**
* @name 基础fetch
* @param {string} url 请求path
* @param {Object} options feich请求配置
* @returns
*/
function baseFetch(url, options) {

// 基础配置
const baseOptions = {
method: "GET", // 默认GET请求
headers: { // 默认请求头
"Content-type": ContentType.json // 默认json数据格式
},
/**
* include:
* 默认不论是不是跨域的请求
* 总是发送请求资源域在本地的 cookies、HTTP Basic authentication 等验证信息
* omit: 从不发送cookies
* same-origin: 同源发送cookies
*/
credentials: 'include'
};

// merge options
options = Object.assign(baseOptions, options);

const {method, body} = options;

// get请求没有请求体,需要将参数拼接到url上
if (method === 'GET' && Object.isObject(body)) {
const paramsArray = [];
Object.keys(body).forEach((key) =>
paramsArray.push(key + "=" + encodeURIComponent(body[key]))
);
if (url.search(/\?/) === -1) {
url += "?" + paramsArray.join("&");
} else {
url += "&" + paramsArray.join("&");
}

// 删除请求体属性
delete options.body;
}

// request interceptors
// 查看当前本地是否有token, 如果有,设置自定义headers中TOKEN
const token = localStorage.getItem(TOKEN);
if (token) options.headers["TOKEN"] = token;

// 利用 Promise.race 实现超时拦截
return Promise.race([
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('request timeout'));
}, TIME_OUT);
}),
new Promise((resolve, reject) => {
window.fetch(url, options)
.then(async res => {

// response interceptors 状态码拦截,对应异常状态吗do something
if(!/^(2|3)\d{2}$/.test(res.status)) {
switch(res.status) {
case 401: //当前用户需要验证(一般是未登陆)
break //一般可以弹出遮盖层,或者回到登陆页面
case 403: // 服务器理解请求,但是拒绝执行,一般是token,session过期
localStorage.removeItem(TOKEN)
break
case 404: // 找不到页面(请求失败,资源在服务器上未找到),可以给一个友好的提示
break
}
return Promise.reject(res)
}
// response interceptors cookies拦截器,存入token
if (res.headers['set-cookies']) {
localStorage.setItem(TOKEN, res.headers['set-cookies']);
}

// return data
const data = options.headers['Content-type'] === ContentType.download ? res.blob() : res.json();
resolve(data);
})
.catch(err => {
reject(err);
});
})
])
}

export const fetchGet = (url, params) => {
return baseFetch(url, {body: params});
}

export const fetchPost = (url, params) => {
return baseFetch(url, {method: 'POST', body: JSON.stringify(params)});
}

export const fetchDownload = (url, params) => {
return baseFetch(url, {
method: 'POST',
body: JSON.stringify(params),
headers: {
"Content-type": ContentType.download
}
});
}