网络-fetch

news2024/11/28 23:38:27

文章目录

  • 前言
  • 一、fetch简介
    • 优点:
    • 缺点:
  • 二、使用
    • get
    • post
    • 进度实现
    • 取消请求
    • 超时实现
  • 总结


前言

本文主要记录浏览器与服务端网络通讯 fetch 的介绍与使用,将完成get、post、进度、取消请求、和超时请求的功能实现。


一、fetch简介

fetch作为继XMLHttpRequest的网络通讯手段,在使用方面极大的简化了使用方法,通过直观的语义化调用方式让代码更具有可读性,但是它对于一些复杂问题确实有待提高,也有一些实验性的更新还在尝试,如获取请求进度、设置超时时间、中断请求等,他自身都不能完成,需要借助外界的力量。

优点:

  • 简洁易用:Fetch API提供了一种简洁的方式来发送网络请求,使用起来非常直观和易于理解。它使用了Promise和链式调用的方式,使得代码更加清晰和可读。
  • 强大灵活:Fetch API支持发送不同类型的请求,如GET、POST、PUT、DELETE等,可以满足各种不同的需求。它还支持设置请求头、发送FormData、上传文件等功能,提供了更多的灵活性和功能性。
  • 支持异步编程:Fetch API基于Promise,可以使用异步编程的方式处理请求和响应。这使得我们可以更好地处理异步操作,避免回调地狱和复杂的嵌套结构。
  • 内置的错误处理:Fetch API内置了错误处理机制,可以通过.catch()方法捕获和处理请求过程中的错误。这使得我们可以更好地处理网络请求中可能出现的问题,提高了代码的健壮性和可靠性。
  • 跨域请求支持:Fetch API支持跨域请求,可以发送跨域请求并处理响应。这对于开发跨域应用或与不同域的API进行通信非常有用。

缺点:

  • 兼容性问题:Fetch API在一些旧版本的浏览器中可能不被完全支持。特别是在IE浏览器中,需要使用Polyfill或者其他库来提供兼容性支持。
  • 不支持取消请求:Fetch API目前不支持取消请求的功能。一旦请求被发送出去,就无法中止或取消。这可能会导致一些问题,特别是在需要处理大量请求或需要及时取消请求的情况下。
  • 不支持超时设置:Fetch API也不支持设置请求的超时时间。如果需要在一定时间内没有响应时取消请求,需要使用其他方式来实现,如使用AbortController和AbortSignal。
  • 无法直接获取请求进度:Fetch API没有提供直接获取请求进度的功能。如果需要获取请求的进度信息,如上传或下载的进度,需要使用其他方式来实现,如使用XMLHttpRequest或其他库。
  • 缺乏一些高级功能:相比于一些第三方库,Fetch API在一些高级功能方面可能有所欠缺。例如,它没有提供自动的请求重试、请求拦截、请求缓存等功能,需要自行实现或使用其他库来满足需求。

二、使用

不用像XMLHttpreques,需要先构造一个XMLHttpreques对象。fetch直接可以使用,就直接 fetch() 使用就行,可以传递;两个参数,参数二在get请求时可不传,fetch默认发送get请求。

  • 参数1:url 请求地址
  • 参数2:对象,对象包括请求方式、头部、请求体
 {
                method:'post',
                headers:{
                    'Content-Type':'application/json'
                },
                body: JSON.stringify({
                    name:'smz'
                })
            }

fetch在第一个then返回的是一个promise ===> fetch的response对象,并不是结果,在这个对象里面包括了请求状态、信息、方法等。在这里需要设置一下返回数据的格式,这个一般和后端沟通好。对请求做处理大都是在这里进行的。

response对象

response

返回格式:

  • text():将响应体解析为纯文本字符串并返回
  • json():将响应体解析为JSON格式并返回一个JS对象
  • blob():将响应体解析为二进制数据并返回一个Blob对象
  • arrayBuffer():将响应体解析为二进制数据并返回一个ArrayBuffer对象
  • formData():将响应体解析为FormData对象

在第二个then中,才是返回的数据,当然,可以通过链式调用catch来处理请求中发生的错误。
下面就进入使用吧。

get

get请求时,第二个参数可不传,默认就是get请求,当然你需要添加请求头之类的可以传第二个参数,这里需要注意的是第一个then里面需要指定返回数据的格式,上面已经给出了几种格式。遇到跨域问题可以看我这个文章 跨域解决 给出了几个跨域的解决方案。

 fetch('http://localhost:3000/api/txt').then(response=>{
            console.log(response)
            //指定返回的格式
            return response.text()
        }).then(data=>{
            console.log(data)
        }).catch(error => {
            // 处理错误
            console.error(error);
        });

post

post请求只要将第二个参数中method属性改为post,headers属性是设置请求头的,body是请求体也就是带的数据。

fetch('http://localhost:3000/api/txt',
            {
                 method:'post',
                 headers:{
                     'Content-Type':'application/json'
                 },
                 body: JSON.stringify({
                     name:'smz'
                 }),
            }
        ).then(response=>{
            console.log(response)
            //指定返回的格式
            return res.json()
        }).then(data=>{
            console.log(data)
        }).catch(error => {
            // 处理错误
            console.error(error);
        });

进度实现

fetch中没有像 XMLHttpRequesprogress事件的loadedtotal属性用来监听请求的进度,所以这个功能只能自己实现。实现思路大致如下:

  • 在第一个then中利用response.body.getReader()返回一个流
// 返回一个流
const reader = response.body.getReader()
  • 利用response.headers.get('Content-Length')获取资源总长度
// 响应头上有总长度信息
const total = response.headers.get('Content-Length')
  • 循环流分片,利用reader.read()得到请求信息,计算当前进度,并传递给元素

每个分片利用reader.read()会得到donevaluedone表示是否完成,value表示当前长度。

let loaded = 0
            while (true){
                const {done,value} = await reader.read()
                if (done){
                    break
                }
                loaded += value.length// 当前进度
                console.log(loaded)
                const progress = document.getElementById('progress')
                progress.innerHTML = `${(loaded/total*100).toFixed(2)+ '%'}`
            }

这里需要注意因为response被getReader()占用了,所以需要提前拷贝一份response,返回用拷贝的response

const res = response.clone()// 拷贝一份,因为被getReader()占用
return res.text()

完整代码:

fetch('http://localhost:3000/api/txt').then(async response=>{
            console.log(response)
            const res = response.clone()// 拷贝一份,因为被getReader()占用
            // 返回一个流
            const reader = response.body.getReader()
            // 响应头上有总长度信息
            const total = response.headers.get('Content-Length')
            let loaded = 0
            while (true){
                const {done,value} = await reader.read()
                if (done){
                    break
                }
                loaded += value.length// 当前进度
                console.log(loaded)
                const progress = document.getElementById('progress')
                progress.innerHTML = `${(loaded/total*100).toFixed(2)+ '%'}`
            }
            //指定返回的格式
            return res.text()
        }).then(data=>{
            console.log(data)
        }).catch(error => {
            // 处理错误
            console.error(error);
        });

进度条

取消请求

同样在fetch中是无法通过它内部API实现请求的中断的,需要借助AbortControllerAbortSignal对象来实现请求中断。

  • 创建了一个AbortController对象
    在请求外部创建AbortController对象
 const controller = new AbortController();
  • 通过controller.signal获取对应的AbortSignal对象。
const signal = controller.signal
  • AbortSignal对象作为Fetch请求的signal选项传递给fetch函数
fetch('http://localhost:3000/api/txt',
            {
                signal // AbortSignal对象
            }
        )
  • 调用controller.abort()方法,触发AbortSignal对象的abort事件,终止Fetch请求
 stop.addEventListener('click',()=>{
        // 终止请求
        controller.abort();
    })
  • 在请求被终止后,进入catch块,进行错误处理。
    需要注意的是,终止请求后,Fetch请求的Promise会被拒绝,并且会抛出一个AbortError错误。因此,在处理错误时,可以通过判断错误类型为AbortError来区分是否是请求被终止的情况。
catch(error => {
            // 处理错误
            if (error.name === 'AbortError'){// 中断请求
                alert('请求被终止')
            }else {
                console.error(error);
            }
        });

使用AbortControllerAbortSignal可以灵活地控制和终止Fetch请求,特别适用于需要及时取消请求的场景,如用户取消操作或超时处理。

中止请求

超时实现

fetch也是不能设置超时时间的。

先定义一个自定义错误,用来标识超时错误

class TimeoutError extends Error {
        constructor(message = '请求超时') {
            super(message)
            this.name = 'TimeoutError'
        }
    }

超时有两种办法:

  1. 使用setTimeout和AbortController实现
    在指定的时间内调用请求终止 controller.abort();
function fetchWithTimeout(url, timeout) {
        return new Promise((resolve, reject) => {
            // 创建一个AbortController对象
            const controller = new AbortController();
            const signal = controller.signal;
            // 设置超时定时器
            const timeoutId = setTimeout(() => {
                // 终止请求
                controller.abort();
                reject(new TimeoutError();
            }, timeout);
            fetch(url, { signal })
                .then(response => {
                    clearTimeout(timeoutId); // 清除超时定时器
                    resolve(response);
                })
                .catch(error => {
                    clearTimeout(timeoutId); // 清除超时定时器
                    reject(error);
                });
        });
    }
  1. 使用setTimeout和Promise.race方法实现
    定义好一个超时promise对象,利用Promise.race()方法返回 超时promise和请求promise对象第一个完成的状态。
    function fetchWithTimeout2(url, timeout) {
        const fetchPromise = fetch(url);
        const timeoutPromise = new Promise((resolve, reject) => {
            setTimeout(() => {
                // 终止请求
                controller.abort();
                reject(new TimeoutError());
            }, timeout);
        });
// 使用Promise.race方法,同时等待fetchPromise和timeoutPromise
        return Promise.race([fetchPromise, timeoutPromise]);
    }

两种方式使用就和fetch使用方式一样。

// fetchWithTimeout('http://localhost:3000/api/txt', 3000)
        fetchWithTimeout2('http://localhost:3000/api/txt', 3000)
            .then(response => response.text())
            .then(data => {
                console.log(data);
            })
            .catch(error => {
                if (error.name === 'TimeoutError'){
                    alert('请求超时,请重试')
                }else {
                    console.error(error);
                }
            });

方式二这里只能将超时实现,并不能将请求杀死,请求还会继续进行,直到后端处理了该请求

超时

完整代码:

 // 超时设置
    // 自定义错误
    class TimeoutError extends Error {
        constructor(message = '请求超时') {
            super(message)
            this.name = 'TimeoutError'
        }
    }
    // 方案一
    function fetchWithTimeout(url, timeout) {
        return new Promise((resolve, reject) => {
            // 创建一个AbortController对象
            const controller = new AbortController();
            const signal = controller.signal;

            // 设置超时定时器
            const timeoutId = setTimeout(() => {
                // 请求中断
                controller.abort();
                reject(new TimeoutError());
            }, timeout);
            fetch(url, { signal })
                .then(response => {
                    clearTimeout(timeoutId); // 清除超时定时器
                    resolve(response);
                })
                .catch(error => {
                    clearTimeout(timeoutId); // 清除超时定时器
                    reject(error);
                });
        });
    }

    // 方案二
    function fetchWithTimeout2(url, timeout) {
        const fetchPromise = fetch(url);
        const timeoutPromise = new Promise((resolve, reject) => {
            setTimeout(() => {
                // 超时
                reject(new TimeoutError());
            }, timeout);
        });
// 使用Promise.race方法,同时等待fetchPromise和timeoutPromise
        return Promise.race([fetchPromise, timeoutPromise]);
    }
    const overtime = ()=>{
        // fetchWithTimeout('http://localhost:3000/api/txt', 300)
        fetchWithTimeout2('http://localhost:3000/api/txt', 300)
            .then(response => response.text())
            .then(data => {
                console.log(data);
            })
            .catch(error => {
                if (error.name === 'TimeoutError'){
                    alert('请求超时,请重试')
                }else {
                    console.error(error);
                }
            });
    }

总结

fetch请求目前来说处理简单请求,日后等fetch API完善吧。其他复杂的请求还是使用ajax来完成,而且还有axiosajax做了封装。这里值得一提的是XMLHttpReques已经不再更新了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1055436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于自适应启动策略的混合交叉动态约束多目标优化算法(MC-DCMOEA)求解CEC2015/CEC2018/CEC2023(MATLAB代码)

一、动态多目标优化问题 1.1问题定义 1.2 动态支配关系定义 二、 基于自适应启动策略的混合交叉动态多目标优化算法 基于自适应启动策略的混合交叉动态多目标优化算法(Mixture Crossover Dynamic Constrained Multi-objective Evolutionary Algorithm Based on Se…

深度学习(1)---卷积神经网络(CNN)

文章目录 一、发展历史1.1 CNN简要说明1.2 猫的视觉实验1.3 新认知机1.4 LeNet-51.5 AlexNet 二、卷积层2.1 图像识别特点2.2 卷积运算2.3 卷积核2.4 填充和步长2.5 卷积计算公式2.6 多通道卷积 三、池化层 一、发展历史 1.1 CNN简要说明 1. 卷积神经网络(Convolut…

【51单片机编写占空比按秒渐亮与渐暗】2023-10-2

昨天刚在W10上安装CH340驱动,又下载到板子上LCD1602定时器时钟程序,为了调试,调用了一个LED观察控制蜂鸣器按秒响的变量,几经调试才发觉该开发板用的是有源蜂鸣器,不用IO取反操作,直接控制IO的高低电平即可…

手机号码格式校验:@Phone(自定义参数校验注解)

需求 新增接口 和 修改接口 中,手机号码的格式校验是普遍需要的。 在每个手机号码字段上添加正则表达式校验注解来实现校验,重复书写,容易出错;在不同的手机号码字段上,可能使用了不同的校验规则,无法有效…

2023年9月文章一览

2023年9月编程人总共更新了4篇文章: 1.2023年8月文章一览 2.Programming abstractions in C阅读笔记:p144-p160 3.Programming abstractions in C阅读笔记:p161-p165 4.我为什么选择这样一份经常出差的工作 9月份大部分时间在出差&#…

【论文阅读】Prototypical Networks for Few-shot Learning

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、论文摘要方法 二、视频总结 前言 本文结合论文和youtube上的视频[Few-shot learning][2.2] Prototypical Networks: intuition, algorithm, pytorch code来…

Spring Boot中的@Controller使用教程

一 Controller使用方法,如下所示: Controller是SpringBoot里最基本的组件,他的作用是把用户提交来的请求通过对URL的匹配,分配个不同的接收器,再进行处理,然后向用户返回结果。下面通过本文给大家介绍Spr…

Linux shell编程学习笔记5:变量命名规则、变量类型、使用变量时要注意的事项

跟其他的高级开发语言一样,Linux Shell编程中使用的数据也需要保存在变量中。 Shell使用变量来控制其行为,并且可以通过更改变量值来更改Shell和其他程序的行为。 我们先来了解一下变量命令的规则、变量类型和使用变量时要注意的事项。 一、变量命名规…

Redis学习笔记(常用数据类型,发布订阅,事务和锁机制,持久化,集群,雪崩,缓存击穿,分布式锁)

一、NoSQL数据库简介 解决扩展性问题,如果需要对功能进行改变(比如增删功能),用框架有一定的规范要求,无形中解决了扩展性问题。 Redis是一种典型的NoSQL数据库。 NoSQL的基础作用: 1. nginx负载均衡反向…

3. 文档操作

1. 创建文档 1.1 创建一个文档 在相应的索引下面使用_doc创建文档,地址为:http://127.0.0.1:9200/students/_doc,创建一个姓名张三的学生信息: {"姓名":"张三","年级":5,"班级":2,&qu…

MySQL数据库——索引(6)-索引使用(覆盖索引与回表查询,前缀索引,单列索引与联合索引 )、索引设计原则、索引总结

目录 索引使用(下) 覆盖索引与回表查询 思考题 前缀索引 语法 示例 前缀长度 前缀索引的查询流程 单列索引与联合索引 索引设计原则 索引总结 1.索引概述 2.索引结构 3.索引分类 4.索引语法 5.SQL性能分析 6.索引使用 7.索引设计…

ORACLE Redo Log Buffer 重做日志缓冲区机制的设计

最近和朋友包括一些国产数据库的研发人员交流,很多程序员认为 Oracle 已经过时,开源数据库或者他们研发的国产数据库才代表数据库发展的未来。甚至在很多交流会议上拿出自家产品的某一个功能点和 Oracle 对比就觉得已经遥遥领先。 实际上数据库系统的发展…

Spring Cloud Alibaba Nacos 配置中心 (配置持久化与动态刷新) 实战

文章目录 一、配置持久化到DB1. 找到配置文件2. 修改配置文件3. 执行数据库SQL4. 控制台创建配置文件 二、集成Nacos配置中心客户端1. 引入依赖2. 添加配置信息3. 创建配置信息4. 编写测试类5. 运行测试6. 动态刷新配置 一、配置持久化到DB 1. 找到配置文件 找到 nacos 的安装…

C#,数值计算——Ranlim32的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// High-quality random generator using only 32-bit arithmetic.Same conventions /// as Ran.Period is 3.11E37 . Recommended only when 64-bit arithmetic is not /// a…

中国1km土壤特征数据集(2010年)

简介&#xff1a; 中国1km土壤特征数据集&#xff08;2010&#xff09;是基于第二次全国土壤调查的中国1:1000000比例尺土壤图和8595个土壤剖面图&#xff0c;以及美国农业部&#xff08;USDA&#xff09;中国区域土地和气候模拟标准&#xff0c;开发了一个多层土壤粒度分布数…

开源layui前端框架 收款码生成系统源码 多合一收款码生成源码 带50多套UI模板

Layui前端的多合一收款码在线生成系统源码_附多套前端UI模板。 卡特三合一收款码生成系统源码&#xff0c;和收款啦采用一样的原理。 内部多达50多套模板&#xff0c;前端跟付款界面都特别好看。 识别收款码之后会自动加密&#xff0c;非常安全。 一样没有后台&#xff0c;一样…

2023年全球接口IP市场发展趋势分析:市占率第二IP品类,受大数据及计算需求推动高速增长[图]

接口IP是基于标准接口协议&#xff0c;实现芯片与内外部设备进行通信、传输数据的电路模块&#xff0c;分为有线接口IP与无线接口IP&#xff0c;主要用于数字信号处理和嵌入式系统中的接口设计。 接口IP分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; …

深度学习:基于长短时记忆网络LSTM实现情感分析

目录 1 LSTM网络介绍 1.1 LSTM概述 1.2 LSTM网络结构 1.3 LSTM门机制 1.4 双向LSTM 2 Pytorch LSTM输入输出 2.1 LSTM参数 2.2 LSTM输入 2.3 LSTM输出 2.4 隐藏层状态初始化 3 基于LSTM实现情感分析 3.1 情感分析介绍 3.2 数据集介绍 3.3 基于pytorch的代码实现 3…

在Windows11家庭中文版中启用Copilot(预览版)

1、下载ViveTool-vx.x.x.zip 2、解压下载的压缩包ViveTool-vx.x.x.zip 3、复制ViveTool文件夹的路径 4、按下wins&#xff0c;打开搜索 5、输入cmd&#xff0c;并选择“以管理员身份运行” 6、在cmd中输入以下命令&#xff0c;进入ViveTool文件夹&#xff1a; cd ViveTool…

【最新版配置conda环境】新版pycharm导入新版anaconda环境

最近下载了新版pycharm和新版anaconda&#xff0c;并且在命令行创建了环境&#xff0c;想着在pycharm里面导入环境。结果现在的导入方式发生了变化。 之前是通过导入Python.exe进行的。 现在&#xff1a; 当我们点击进去之后&#xff0c;会发现找不到python.exe了。 具体什么…