Fetch&Fetch的二次封装

2023-11-06

前言

客户端服务器端通信方式ajax (ajax JQ的类库 /axios类库)  /jsonp  / fetch

fetch是Es6新提供的API:基于不同于​XMLHttpRequest的方式,基于客户端和服务器端的数据通信,而且本身是基于promise管理请求结果的(发送请求返回promi实例)

fetch的基础知识和管理

语法:

Promise<Response> fetch(input[, init]); :返回promise实例 input:URL地址 init:配置项

  • 基于fetch发送请求,只要服务器有响应结果,fetch都认为是成功的<promise的状态是fulfilled>
  • 默认情况下只有 断网 ,请求中断,请求超时等请况下,服务器不会有任何响应,fetch才会认为当前请求是失败的!!
  • 在成功的THEN方法中,我们需要根据HTTP状态码,手动校验成功还是失败!
  • 还需要把响应主体body中存储的数据变为想要的,一般都要json格式,并且监听是否转换成功

fetch目前不如XMLHttpRequest的机制完善(例如fetch中没有设置请求超时和请求中断的方法)

  • fetch请求超时如何处理:自己在发送请求后,设置定时器监听,如果请求先到则删掉定时器,如果定时器先到,则直接走catch失败情况
  • 对于中断请求目前有一个草案阶段的API可以实现AbortController

Response内置类

  • 返回的response对象是Response类的实例
  • status/statusText:http状态码及其描述
  • ok:状态码是200时为true
  • Response.headers 包含此 Response 所关联的 Headers 对象。
  • Response.redirected  表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个条目。
  • Response.type  包含 Response 的类型(例如,basic、cors)是否跨域
  • Response.url  包含 Response 的URL。
  • Response.useFinalURL 包含了一个布尔值,来标示这是否是该 Response 的最终 URL Response 实现了 Body 接口,所以以下属性亦可用:
  • Body.body 一个简单的 getter,用于暴露一个 ReadableStream 类型的 body 内容。
  • Body.bodyUsed  包含了一个布尔值来标示该 Response 是否读取过 Body。

Response.prototype

这些方法的目的是:把body可读流对象解析出指定格式的数据 例如调用Response.json()会返回一个json格式对象的数据

执行方法会返回一个全新的promise,实例存储的值是想要的数据:服务器返回的响应主体内容有很多,当我们想执行某个方法转换为想要格式的时候,可能会成功,也可能会失败,所以在次基于promise管理

  • arrayBuffer() Buffer格式
  • blob()  二进制格式
  • neienformData()  文件上传 表单上传
  • json() json格式字符串
  • text()  纯字符串格式
  • Response.clone() 创建一个 Response 对象的克隆。
  • Response.error()返回一个绑定了网络错误的新的 Response 对象。
  • Response.redirect()  用另一个 URL 创建一个新的 Response。 Response 实现了 Body 接口,所以以下方法同样可用:

Headers内置类

headers:Headers内置类的实例对象(可以对请求头响应头信息做管理)

  • append /delete/ set:设置请求头/响应头
  • forEach/get/has/获取请求头/响应头
  • keys/entries/values迭代器信息

ReadableStream内置类

body:ReadableStream内置类的实例对象(可读流 存储服务器返回的响应主体信息)

init 配置项

一个配置项对象,包括所有对请求的设置。可选的参数有:

  • method: 请求方式:GET*/POST/DELETE/HEAD/PUT...
  • headers设置请求头信息 自定义请求头信息{Headers对象 & 普通对象}
  • body: 设置请求主体信息(只有post系列请求才可以设置,get系列请求会报错,格式有要求:json字符串,URLENCODED格式字符串,普通字符串,FormData格式对象,Buffer/bolb格式...不能是普通对象,并且要根据请求主体的数据格式,配置相关的请求头(Content-Type)
  • mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
  • credentials: 是否允许携带资源凭证 include(同源跨域都允许)same-origin(同源才允许)omit都不允许
  • cache:  请求的 cache 模式: default、 no-store、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。
  • redirect: 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在Chrome中默认使用follow(Chrome 47之前的默认值是manual)。
  • referrer: 一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client。
  • referrerPolicy: 指定了HTTP头部referer字段的值。可能为以下值之一: no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。
  • integrity: 包括请求的  subresource integrity 值 

[扫盲] 客户端基于请求主体传递给服务器的格式

  • json字符串
  • urlenccoded格式字符串
  • formData格式对象

代码

import { Message } from 'element-ui';
//创造一个中断控制器
let controller = new AbortController();
//自定义请求头信息{Headers对象 & 普通对象}
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded')
headers.append('name', 'lisa')
fetch('/api/getTaskList', {
    method: 'GET',//请求方式:GET*/POST/DELETE/HEAD/PUT...
    headers,//设置请求头信息
    body: '',//设置请求主体信息(只有post系列请求才可以设置,get系列请求会报错,格式有要求:json字符串,URLENCODED格式字符串,普通字符串,FormData格式对象,Buffer/bolb格式...不能是普通对象,并且要根据请求主体的数据格式,配置相关的请求头(Content-Type)
    credentials: 'include',//是否允许携带资源凭证 include(同源跨域都允许)same-origin(同源才允许)omit都不允许
    //给fetch请求设置信号器
    signal: controller.signal
})
    .then(response => {
        let { status, statusText } = response;
        if (!/^2\d{2}$/.test(status)) {
            //失败:状态码不对 
            return Promise.reject({
                code: 100,
                status,
                statusText
            });
        }
        //转换如果失败,走到catch,转换成功走下一个THEN
        return response.json().catch(resone => {
            return Promise.reject({
                code: 200,
                message: resone.message
            });
        });

    })
    .then(value => {
        console.log('成功', value);
    })
    .catch(resone => {
        //状态码不是2开始的[code=100],转换响应主体格式失败[code=200],请求中断[code=20],断网
        let { code, status } = resone || {};
        if (code === 100) {
            switch (+status) {
                case 404:
                    Message.error('请求地址错误');
                //...
            }
        } else if (code === 200) {
            Message.error('请求格式转换失败');
        } else if (code === 20) {
            Message.error('请求中断');
        } else {
            Message.error('网路出现异常');
        }
    });
//中断请求
// controller.abort();

fetch的二次封装

封装request([config])

// 核心方法

  •  url请求地址
  •  method  请求方式:GET/POST/DELETE/HEAD/PUT...
  •  credentials 携带资源凭证 include(同源跨域都允许)same-origin(同源才允许)omit都不允许
  •  headers()自定义请求头信息(格式必须是纯粹对象),根据当前服务器要求,如果用户传的是一个纯粹对象,我们需要把其变为urlencoded格式字符串,设置请求头中的Content-type...
  •  body null 请求主体信息(只针对于post系列请求,)
  • params:设置问号传参信息(格式必须是纯粹对象) 我们在其内部把其拼接到url的末尾
  • responseType 预设服务器返回结果读取方式:JSON/text/arraybuffer/blob
  • signal 中断请求的信号

// 快捷方法

  • request.get/head/delete/options([url],[config]):预先指定配置项中的url/method
  • request.post/put/patch([url],[body],[config]):预选指定了配置项中的url /method/body
  • request.abort 中断当前请求
import qs from 'qs';
import { isPlainObject } from '../assets/utils';
import { message } from 'antd';

/* 核心方法 */
const http = function http(config) {
    // init config & validate
    if (!isPlainObject(config)) config = {};
    config = Object.assign({
        url: '',
        method: 'GET',
        credentials: 'include',
        headers: null,
        body: null,
        params: null,
        responseType: 'json',
        signal: null
    }, config);
    if (!isPlainObject(config.headers)) config.headers = {};
    if (config.params !== null && !isPlainObject(config.params)) config.params = null;
    let { url, method, credentials, headers, body, params, responseType, signal } = config;

    // 处理URL:params存在,我们需要把params中的每一项拼接到URL末尾
    if (params) url += `${url.includes('?') ? '&' : '?'}${qs.stringify(params)}`;

    // 处理请求主体:只针对于POST系列请求;body是个纯粹对象,根据当前后台要求,把其变为urlencoded格式!
    if (isPlainObject(body)) {
        body = qs.stringify(body);
        headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }

    // 类似于Axios的请求拦截器,例如:把存储在客户端本地的token信息携带给服务器「根据当前后台要求处理」
    let token = localStorage.getItem('token');
    if (token) headers['authorzation'] = token;

    // 发送请求
    method = method.toUpperCase();
    config = {
        method,
        credentials,
        headers,
        cache: 'no-cache',
        mode: 'cors'
    };
    if (/^(POST|PUT|PATCH)$/i.test(method) && body) config.body = body;
    if (signal) config.signal = signal;
    return fetch(url, config).then(response => {
        // 成功则返回响应主体信息
        let { status, statusText } = response,
            result;
        if (!/^(2|3)\d{2}$/.test(status)) return Promise.reject({ code: -1, status, statusText });
        switch (responseType.toLowerCase()) {
            case 'text':
                result = response.text();
                break;
            case 'arraybuffer':
                result = response.arrayBuffer();
                break;
            case 'blob':
                result = response.blob();
                break;
            default:
                result = response.json();
        }
        return result.then(null, reason => Promise.reject({ code: -2, reason }));
    }).catch(reason => {
        // 根据不同的失败情况做不同的统一提示
        /* let code = reason?.code;
        if (+code === -1) {
            // 状态码问题
            switch (+reason.status) {
                case 404:
                    // ...
                    break;
            }
        } else if (+code === -1) {
            // 读取数据出现问题
        } else if (+code === 20) {
            // 请求被中断
        } else {
            // 网络问题
        } */
        message.error('小主,当前网络出现异常,请稍后再试~~');
        return Promise.reject(reason);
    });
};

/* 快捷方法 */
['GET', 'HEAD', 'DELETE', 'OPTIONS'].forEach(item => {
    http[item.toLowerCase()] = function (url, config) {
        if (!isPlainObject(config)) config = {};
        config['url'] = url;
        config['method'] = item;
        return http(config);
    };
});
['POST', 'PUT', 'PATCH'].forEach(item => {
    http[item.toLowerCase()] = function (url, body, config) {
        if (!isPlainObject(config)) config = {};
        config['url'] = url;
        config['method'] = item;
        config['body'] = body;
        return http(config);
    };
});

export default http;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Fetch&Fetch的二次封装 的相关文章

随机推荐

  • 【MySQL高级篇笔记-数据库备份与恢复(下) 】

    此笔记为尚硅谷MySQL高级篇部分内容 目录 一 物理备份与逻辑备份 二 mysqldump实现逻辑备份 1 备份一个数据库 2 备份全部数据库 3 备份部分数据库 4 备份部分表 5 备份单表的部分数据 6 排除某些表的备份 7 只备份结
  • 【VSCode】Windows系统的WSL无法启动vscode问题

    在WSL环境中无法启动vscode时 有可能是 WSL 插件的影响 可以使用下面的步骤来解决 Open VS Code on Windows Open Extensions and then search on WSL It should
  • Qt使用Qt Designer进行界面设计

    上一章我们使用代码直接进行界面设计 这一章我们使用Qt Designer进行界面设计 简单直接 所见即所得 大大提高了工作效率 特别是对于复杂界面 1熟悉Qt Designer Qt Designer是Qt专为界面设计做的软件 使得用户能够
  • 使用Python和OpenCV进行图像拼接和全景图构建

    使用Python和OpenCV进行图像拼接和全景图构建 1 效果图 2 原理及步骤 3 源码 3 1 拼接类源码 3 2 拼接用到的工具类 3 3 叠加多张图像源码 参考 这篇博客将介绍如何使用OpenCV执行图像拼接和全景构建 即给定两个
  • Hana Studio开发简介

    Hana Studio作为SAP官方的IDE 工具 推出也有一段时间了 就目前使用的情况来看 如果是做常规S 4开发 SAP GUI还是首要选择 一 IDE安装路径 链接 https pan baidu com s 1qMg8duocTa3
  • pyqt5实现按钮单窗口多页面切换

    1 使用QT Designer进行设计 创建一个MainWindow 从左侧选出Push Button Stacked Widget分别拖到我们的MainWindow里 怕看不见Stacked Widget 给他上个色 在QT Design
  • vant-weapp Area 省市区选择的使用及遇到的坑

    json中 导入 van area vant weapp area index 基础用法
  • SpringCloud gateway (史上最全)

    1 1 SpringCloud Gateway 简介 SpringCloud Gateway 是 Spring Cloud 的一个全新项目 该项目是基于 Spring 5 0 Spring Boot 2 0 和 Project Reacto
  • Kubernetes踩坑(二): Service IP(LVS)间断性TCP连接故障排查

    问题阶段 一 用户反应某个redis使用卡顿 连接该redis服务使用的是svc代理 即ipvs snat的方式 ipvsadm L发现 VIP收到的6379端口的数据包 会以rr的方式分别转发到pod的80 6379端口上 相当于会有50
  • mysql增加分区

    增加分区 是修改原有分区 从而替换现有分区 ALTERTABLE xxx表 PARTITION BY RANGE COLUMNS CREATE TIME PARTITION p20210901 VALUES LESS THAN 2021 1
  • 【华为OD机试c++】最长广播效应【2023 B卷

    题目描述 某通信网络中有N个网络结点 用1到N进行标识 网络中的结点互联互通 且结点之间的消息传递有时延 相连结点的时延均为一个时间单位 现给定网络结点的连接关系link i u v 其中u和v表示网络结点 当指定一个结点向其他结点进行广播
  • linux grep 带空格的内容,或者搜索多个单词,一段话

    错误示范 more xxx log grep UPDATE user info 正确方法 more xxx log grep UPDATE user info
  • 第23讲 Python range 数据类型

    您的 关注 和 点赞 是认可 是支持 是动力 如意见相佐 可留言 本人必将竭尽全力试图做到准确和全面 终其一生进行修改补充更新 本文首发在IT羊资源网 IT羊资源网 网址 https www ityangzy com IT羊资源网是IT世界
  • GB9706.1-2007+2020和IEC60601-1:2005 3.0+2012 3.1标准主要差异解析

    目录 GB9706 1 2007医用电气设备 第1部分 安全通用要求 GB9706 1 2020医用电气设备 第1部分 基本安全和基本性能的通用要求 IEC60601 1 第二版和第三版差异 1 最关键变化 2 新术语名词引用 3 设备分类
  • [1022]Hive insert 字段表错位

    文章目录 Hive insert 字段表错位踩坑 1 问题描述 2 排查过程 3 问题定位 4 解决方案 hive的insert语句列顺序问题以及新增字段遇到的坑 insert语句列顺序 对新增字段插入数据再查询发现是NULL Hive i
  • 技术管理主要做什么?

    最近一直在思考技术转管理过程中需要注意到的一些事情 现在就总结下分享给大家看看 核心职责 确定团队目标 不论项目大小 一定要有目标 有目标才能让所有人看到方向 明确每天工作的意义 单纯技术人员应该切换思维为全局性 而不局限于技术层面 现在个
  • 某盾滑块js逆向

    注 本篇博客仅供学习使用 请勿用做其他商业用途 如有侵权 请联系本菜鸟删除 本小菜鸟已经快两个月没更新文章了 一年总有那么356天不想努力 就想躺平 最开始学习js逆向的时候 用Python算法还原了某盾的空间推理 到现在已经过去半年多 这
  • Mybaties-plus 分页使用

    1 简介 查询分页分为物理分页和逻辑分页 1 逻辑分页 一次性查出所有数据 然后在内存中筛选需要的数据 缺点 大数据量时容易造成内存溢出 因为是一次性查出每次返回需要的所有数据时效性低不推荐使用 2 物理分页 通过sql 的limit 去控
  • 联想小新Pro14安装Ubuntu后无法进入系统、亮度无法调节、蓝牙无法打开、输入卡顿延迟等问题的解决办法

    联想小新Pro14安装Ubuntu后无法进入系统 亮度无法调节 蓝牙无法打开等问题的解决办法 前言 月初买了台联想小新Pro14 AMD锐龙5800H版本 在安装Ubuntu 20 04 2 LTS 系统时遇到了一些问题 所幸在众多网友前辈
  • Fetch&Fetch的二次封装

    前言 客户端服务器端通信方式ajax ajax JQ的类库 axios类库 jsonp fetch fetch是Es6新提供的API 基于不同于 XMLHttpRequest的方式 基于客户端和服务器端的数据通信 而且本身是基于promis