背景
接手公司的一个浙里办的项目, 由于接口请求实在太乱 , 遂找个时间简化一下 且项目代码还是复用以前的项目,还有很多冗余无用的代码, 如果有读者读到, 可以交流一下解构的思路
源代码如下:
jsx
let requestNum = 0;
// 请求地址为一下数组项时,请求不带请求头
const ignoreHeader = //省略
function beginLoading(noLoading) {
if (noLoading) return;
if (requestNum === 0) {
uni.showLoading({
title: "加载中",
});
}
requestNum++;
}
function endLoading(noLoading) {
if (noLoading) return;
requestNum--;
if (requestNum <= 0) {
requestNum = 0;
uni.hideLoading();
}
}
function getAppId() {
//省略
return appId;
}
function fetch(url, type = "get", data = {}, dataType, noLoading = false) {
beginLoading(noLoading);
return new Promise((resolve, reject) => {
(url && url.startsWith("mgop.alibaba") )? handleMgop(url, type, data, dataType, noLoading, resolve, reject) : handleFetch(url, type, data, dataType, noLoading, resolve, reject);
});
}
function uploadImg(url, filePath, formData = {}, noLoading = false) {
//省略
}
function download(url, type = "get", data = {}, noLoading = false) {
//省略
}
// 通用版upload,支持files或filePath方式上传
function commonUpload(config = { noLoading: false }) {
//省略
}
function handleMgop(url, type, data, dataType, noLoading, resolve, reject) {
//省略
//这里原来错误的做法是把所有的数据处理, 包括针对错误的处理全都放在了这里
}
function handleFetch(url, type, data, dataType, noLoading, resolve, reject) {
//省略
//这里原来错误的做法是把所有的数据处理, 包括针对错误的处理全都放在了这里
}
export { uploadImg, fetch, download, commonUpload };
整体框架
不要把fetch放到api文件夹里面, 功能之间要有明显的区分
这里我放在了utils文件夹里面, 新建了一个fetch文件夹, 共有下面几个文件
index.js : 入口文件
handleReqLoading.js: 全局loading工具函数
errCode.js: 后端错误代码对应的json(值和value)
requestHandler.js : 请求处理器
responsehandler.js : 响应处理器
思路
第一步:
index.js导出 myFetch函数 , 这个作为请求函数, 应该只包含 :
- 请求配置
- 获取请求信息
- 处理请求信息
- 返回promise结果
- 处理http错误
故代码如下:
jsx
/**
* 封装请求
* @param url 请求地址
* @param type 请求方式
* @param data 请求参数
* @param dataType 请求数据类型
*/
export const myFetch = async (url, type = "get", data = {}, dataType) => {
const reqConfig = {
url: httpApi + url,
method: type,
data: data,
dataType: dataType,
timeout: 60000,
header: {
'content-type': 'application/json',
Token: '1'
},
}
try {
handleReqLoading(true);
const response = await handleRequest(reqConfig);
const responseData = handleNormalResponse(response);
handleReqLoading(false);
//返回一个promise对象
return responseData;
}catch (err) {
return handleHttpError(err);
}
}
这里把 处理错误信息, 处理请求, 处理相应 单独拿了出来, 方便以后扩展修改
处理请求(requestHandler.js)
这里把具体使用 uni.request.js的处理逻辑单独封装了起来, 它的职责就是, 接收请求配置, 发起请求, 返回 正确或错误的相应信息,
这里返回一个promise的原因是等待 接口请求, 父函数 await , 这样response 就是接口的响应值了
jsx
export const handleRequest = async (reqConfig) => {
return new Promise((resolve, reject) => {
uni.request({
...reqConfig,
success: function (res) {
resolve(res);
},
fail: function (err) {
reject(err);
},
});
});
}
处理响应(responseHandler.js)
分为: 处理状态码为200 和不为200的响应
handleHttpError
这里使用errcode.js中的json来找出提示信息, 进行提示
jsx
/**
* 处理状态码不为200的响应
*/
export function handleHttpError(err) {
const msg = errCodeMsgKV[err.code] + ':' + err.msg || err.msg;
uni.showToast({
title: msg,
icon: "none",
duration: 2000,
});
return Promise.reject(msg);
}
/** errCode.js */
export const ErrCode = {
/* 成功 */
SUCCESS : 0,
/* 系统内部错误 */
SYSTEM_ERROR : 500,
/* 不存在该资源 */
NOT_FOUND : 404,
}
export const errCodeMsgKV = {
[ErrCode.SUCCESS]: '成功',
[ErrCode.SYSTEM_ERROR]: '系统内部错误',
[ErrCode.NOT_FOUND]: '不存在该资源',
}
除了状态码的处理, 后端实际上应该要根据不同的业务返回不同的code, 然后前端定义一个businessErrcodeKV的json来对应提示, 后端目前不太规范, 会有返回状态码为200的 ,目前后端会有状态码为200, code为0, msg是提示错误信息的情况存在
handleNormalResponse
处理状态码为200的情况
除了状态码的处理, 后端实际上应该要根据不同的业务返回不同的code, 然后前端定义一个businessErrcodeKV的json来对应提示, 后端目前不太规范, 会有返回状态码为200的 ,目前后端会有状态码为200, code为0, msg是提示错误信息的情况存在
返回一个promise, 以便调用myfetch可以使用 .then
这个函数就可以根据不同的状态码来进行不同的逻辑操作了, 错误的统一处理在归纳在了myfetch文件夹里面, 这样 接口请求的时候更加简洁
jsx
/**
* 处理http响应码为200的响应
* @return {Promise<unknown>}
*/
export function handleNormalResponse(res) {
return new Promise((resolve, reject) => {
if (res.statusCode || res.statusCode === 0) {
switch (res.statusCode) {
case 200:
resolve(res.data);
break;
case 0:
resolve(res.data);
break;
default:
reject(res.data);
uni.showToast({
title:res.data.msg,
icon: "none",
duration: 2000,
});
}
} else {
reject(res.data);
uni.showToast({
title: "服务异常",
icon: "none",
duration: 2000,
});
}
});
}