封装 fetch 与 Error,返回 Promise 对象
时间:2021-07-20
本文章向大家介绍封装 fetch 与 Error,返回 Promise 对象,主要包括封装 fetch 与 Error,返回 Promise 对象使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
fetch 在目前已经是很成熟的请求资源的方法,但为了方便在项目中调用,一般都会进行二次封装
一、定义错误类型
对于封装公共组件或方法,一定要多想,七分设计,三分开发
而对于一个网络请求来说,除了处理请求体、响应体之外,还有一个常常被忽略的环节,那就是定义 Error
项目中关于网络请求的错误有很多种,比如超时错误、服务器错误、断网错误,这些都可以加以封装
// errors.js
export class ApiError extends Error {
constructor(message, url) {
super(message);
this.message = message;
this.name = 'ApiError';
this.url = url;
}
}
export class DisconnectError extends ApiError {
constructor(url) {
super('网络已断开,请重新连接', url);
this.name = 'DisconnectError';
}
}
export class ApiServerError extends ApiError {
constructor(statusCode, url) {
super(`请求服务器出错:${statusCode}`, url);
this.name = 'ApiServerError';
this.statusCode = statusCode;
}
}
export class ApiJsonError extends ApiError {
constructor(url) {
super('请求服务器出错:无法转换为JSON', url);
this.name = 'ApiJsonError';
}
}
export class ApiTimeoutError extends ApiError {
constructor(time, url) {
super('请求超时', url);
this.name = 'ApiTimeoutError';
this.time = time;
}
}
上面定义了几种常见的请求错误,其实还可以定义一种业务错误
比如某个请求的状态是 200,但不符合后端定义的业务逻辑,返回了特殊的 code
这时就可以根据后端返回的 code 进行业务错误的封装
二、抛出错误
在抛出上面定义的 Error 的时候,需要做一些判断,这部分逻辑可以抽出来
// 检查网络状态是否已连接
function checkonLine(url) {
return new Promise((resolve, reject) => {
if (!window.navigator.onLine) {
reject(new DisconnectError(url));
} else {
resolve(url);
}
});
}
// 校验状态码
function checkStatus(response) {
const status = Number(response.status);
if (status >= 200 && status < 300) {
return response;
}
throw new ApiServerError(status, response.url);
}
// 解析 fetch 的响应结果
function parseJSON(response) {
return new Promise((resolve, reject) => {
response
.json()
.then((json) => {
// 记录请求的地址
// eslint-disable-next-line
json._SERVER_URL = response.url;
resolve(json);
})
.catch((error) => {
if (error instanceof SyntaxError) {
reject(new ApiJsonError(response.url));
} else {
reject(error);
}
});
});
}
三、封装 fetch
准备就绪,可以上主菜了
const FETCH_TIMEOUT = 1000 * 30;
function request(path, params, options = {}) {
const { body, method = 'GET', ...other } = params || {};
const newMethod = `${method}`.toUpperCase();
const newParams = { method: newMethod, credentials: 'include', ...other };
const timeout = newParams.timeout || FETCH_TIMEOUT;
let url = path;
if (newMethod !== 'GET') {
if (!(body instanceof FormData)) {
newParams.headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
...newParams.headers,
};
newParams.body = JSON.stringify(body);
}
} else {
// 对GET请求增加时间戳 以避免IE缓存
const timestamp = Date.now();
const queryURL = qs.stringify({ ...body, t: timestamp });
url = `${url}?${queryURL}`;
}
// 封装请求头
newParams.headers = {
...newParams.headers,
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
credentials: 'include',
};
return Promise.race([
// 校验网络连接
checkonLine(url)
.then(() => {
return fetch(url, newParams, options);
})
.then(checkStatus)
.then(parseJSON)
.catch((err) => {
throw err;
}),
new Promise((resolve, reject) => {
setTimeout(reject, timeout, new ApiTimeoutError(timeout, url));
}),
]);
}
请求函数 request 已经搞定,这时可以简单的粗暴的 export 这个函数
也可以导出具体的 get、post 方法
export default {
get: async (path, params, options) =>
request(path, { method: 'GET', body: params }, options),
post: async (path, params, options) =>
request(path, { method: 'POST', body: params }, options),
delete: async (path, params, options) =>
request(path, { method: 'DELETE', body: params }, options),
put: async (path, params, options) =>
request(path, { method: 'PUT', body: params }, options),
};
四、更进一步
上面的代码导出的是一个含有 get 等方法的对象,需要这么使用:
import http from './request'
http.get('/api/get', { name: 'wise' });
http.post('/api/save', { name: 'wise' });
不过对于 get 请求,很多的库做了进一步的封装,可以直接调用
// 直接调用,默认使用 get 请求
http('/api/get', { name: 'wise' });
为了更好的体验,我们的代码也可以更进一步:
const http = (url) => {
return http.get(url);
};
http.get = async (path, params, options) =>
request(path, { method: 'GET', body: params }, options);
http.post = async (path, params, options) =>
request(path, { method: 'POST', body: params }, options);
http.delete = async (path, params, options) =>
request(path, { method: 'DELETE', body: params }, options);
http.put = async (path, params, options) =>
request(path, { method: 'PUT', body: params }, options);
export default http;
搞定~
原文地址:https://www.cnblogs.com/wisewrong/p/15031654.html
- [喵咪Liunx(3)]端口转发工具rinetd
- 基于PhalApi的Smarty拓展
- PhalGo-参数验证过滤
- [喵咪Redis]Redis配置文件和主从设置
- [喵咪Redis]Redis-Sentinel
- [喵咪Redis]Redis安装与介绍
- [喵咪Liunx(4)Monit进程监控
- 【第四期】GC专题
- ML中相似性度量和距离的计算&Python实现
- ASP.NET MVC Model元数据及其定制: Model元数据的定制
- 小白也可以操作的手机TensorFlow教程:Android版和iOS版
- PhalApi-PHPExcel基于PhalApi的PHPExcel拓展
- [喵咪软件推荐(2)]全球服务器测速工具speedtest-cli
- 使用Keras创建一个卷积神经网络模型,可对手写数字进行识别
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android EditText实现输入表情
- Android编程实现使用Intent传输包含自定义类的ArrayList示例
- EditText实现输入限制和校验功能实例代码
- java零基础入门006~springboot实现多文件的上传(java多文件的上传)
- Android编程实现随机生成颜色的方法示例
- Android中将Bitmap对象以PNG格式保存在内部存储中的方法
- python入门012~使用python3爬取网络图片并保存到本地
- java入门015~springboot2整合mybatis,轻松实现mysql数据的增删改查
- 详解Android activity与fragment之间的通信交互
- Android App内监听截图加二维码功能代码
- 微信小程序登录与注册验证码倒计时的效果实现
- Android仿微信朋友圈全文、收起功能的实例代码
- TextView实现图文混合编排的方法
- 小程序云函数调用http或https请求外部数据
- 详解Android中图片的三级缓存及实例