This repository has been archived by the owner on Feb 21, 2022. It is now read-only.
forked from cloud-templates/vue-preset
-
Notifications
You must be signed in to change notification settings - Fork 14
/
request.js
274 lines (247 loc) · 7.91 KB
/
request.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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/**
*
* @authors liwb (lwbhtml@gmail.com)
* @date 2018/6/5 上午10:43
* @description https://github.com/mzabriskie/axios
* 安卓4.4.3一下的手机还是不支持Promise的,需要引入npm install babel-polyfill和npm install babel-runtime,在入口文件上加上即可
* import 'babel-polyfill';
*/
import Qs from "qs";
import axios from "axios";
import autoMatchBaseUrl from "./autoMatchBaseUrl";
import { TIMEOUT, HOME_PREFIX } from "@/constant";
import { addPending, removePending } from "./pending";
const codeMessage = {
200: "服务器成功返回请求的数据。",
201: "新建或修改数据成功。",
202: "一个请求已经进入后台排队(异步任务)。",
204: "删除数据成功。",
400: "发出的请求有错误,服务器没有进行新建或修改数据的操作。",
401: "用户没有权限(令牌、用户名、密码错误)。",
403: "用户得到授权,但是访问是被禁止的。",
404: "发出的请求针对的是不存在的记录,服务器没有进行操作。",
406: "请求的格式不可得。",
410: "请求的资源被永久删除,且不会再得到的。",
422: "当创建一个对象时,发生一个验证错误。",
500: "服务器发生错误,请检查服务器。",
502: "网关错误。",
503: "服务不可用,服务器暂时过载或维护。",
504: "网关超时。",
};
/**
* 拦截到失败的请求以后,尽可能重试
* https://github.com/axios/axios/issues/164#issuecomment-327837467
*/
const retry = function (error) {
const { response, config } = error;
// 判断是否配置了重试
if (!config || !config.retry) {
if (response) {
// 请求已发出,但是不在2xx的范围
// 对返回的错误进行一些处理
return Promise.reject(checkStatus(response));
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
console.log("断网了~");
}
return Promise.reject(error);
}
// 设置重置次数,默认为0
config.__retryCount = config.__retryCount || 0;
// 判断是否超过了重试次数
if (config.__retryCount >= config.retry) {
if (response) {
// 请求已发出,但是不在2xx的范围
// 对返回的错误进行一些处理
return Promise.reject(checkStatus(response));
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
console.log("断网了~");
}
return Promise.reject(error);
}
// 重试次数自增
config.__retryCount += 1;
const backOffDelay = config.retryDelay
? (1 / 2) * (Math.pow(2, config.__retryCount) - 1) * 1000
: 1;
// 延时处理
const backoff = new Promise((resolve) => {
setTimeout(() => {
resolve();
}, backOffDelay);
});
// 重新发起axios请求
return backoff.then(() => {
return axios(config);
});
};
/**
* 全局请求扩展配置
* 添加一个请求拦截器 (于transformRequest之前处理)
*/
const axiosConfig = {
success: (config) => {
// 将当前请求添加到 pending 中
addPending(config);
// 以下代码,鉴权token,可根据具体业务增删。
// demo示例:
if (~config["url"].indexOf("operatorQry")) {
config.headers["accessToken"] =
"de4738c67e1bb450be71b660f0716aa4675860cec1ff9bc23d800efb40519cf3";
}
return config;
},
error: (error) => Promise.reject(error),
};
/**
* 全局请求响应处理
* 添加一个返回拦截器 (于transformResponse之后处理)
* 返回的数据类型默认是json,若是其他类型(text)就会出现问题,因此用try,catch捕获异常
*/
const axiosResponse = {
success: (response) => {
// 在请求结束后,移除本次请求
removePending(response);
responseLog(response);
return checkStatus(response);
},
error: (error) => {
const { response, code } = error;
if (axios.isCancel(error)) {
console.error("repeated request: " + error.message);
} else {
// handle error code
}
// 接口请求异常统一处理
if (code === "ECONNABORTED") {
// Timeout error
console.log("Timeout error", code);
}
return retry(error);
},
};
function responseLog(response) {
if (process.env.NODE_ENV === "development") {
const randomColor = `rgba(${Math.round(Math.random() * 255)},${Math.round(
Math.random() * 255
)},${Math.round(Math.random() * 255)})`;
console.log(
"%c┍------------------------------------------------------------------┑",
`color:${randomColor};`
);
console.log("| 请求地址:", response.config.url);
console.log("| 请求参数:", Qs.parse(response.config.data));
console.log("| 返回数据:", response.data);
console.log(
"%c┕------------------------------------------------------------------┙",
`color:${randomColor};`
);
}
}
function checkStatus(response) {
// 如果http状态码正常,则直接返回数据
if (response) {
const { status, statusText } = response;
if ((status >= 200 && status < 300) || status === 304) {
// 如果不需要除了data之外的数据,可以直接 return response.data
return response.data;
}
return {
status,
msg: codeMessage[status] || statusText,
};
}
// 异常状态下,把错误信息返回去
return {
status: -404,
msg: "网络异常",
};
}
axios.interceptors.request.use(axiosConfig.success, axiosConfig.error);
axios.interceptors.response.use(axiosResponse.success, axiosResponse.error);
/**
* 基于axios ajax请求
* @param url
* @param method
* @param timeout
* @param prefix 用来拼接url地址
* @param data
* @param headers
* @param dataType
* @returns {Promise.<T>}
*/
export default function request(
url,
{
method = "post",
timeout = TIMEOUT,
prefix = HOME_PREFIX,
data = {},
headers = {},
dataType = "json",
}
) {
const baseURL = autoMatchBaseUrl(prefix);
headers = Object.assign(
{
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
headers
);
const retryParams = { retry: 3, retryDelay: 1000 };
const defaultConfig = {
baseURL,
url,
method,
params: data,
data,
timeout,
headers,
responseType: dataType,
...retryParams,
};
if (method === "get") {
delete defaultConfig.data;
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
if (data !== undefined) {
defaultConfig.params = Object.assign(defaultConfig.params, {
_t: new Date().getTime(),
});
} else {
defaultConfig.params = { _t: new Date().getTime() };
}
} else {
delete defaultConfig.params;
const contentType = headers["Content-Type"];
if (typeof contentType !== "undefined") {
if (~contentType.indexOf("multipart")) {
// 类型 `multipart/form-data;`
defaultConfig.data = data;
} else if (~contentType.indexOf("json")) {
// 类型 `application/json`
// 服务器收到的raw body(原始数据) "{name:"jhon",sex:"man"}"(普通字符串)
defaultConfig.data = JSON.stringify(data);
} else {
// 类型 `application/x-www-form-urlencoded`
// 服务器收到的raw body(原始数据) name=homeway&key=nokey
defaultConfig.data = Qs.stringify(data);
}
}
}
return axios(defaultConfig);
}
// 上传文件封装
export const uploadFile = (url, formData) => {
return request(url, {
method: "post",
data: formData,
headers: { "Content-Type": "multipart/form-data" },
});
};