网络-fetch


文章目录

  • 前言
  • 一、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 = 0while (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 = 0while (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和timeoutPromisereturn 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和timeoutPromisereturn 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.rhkb.cn/news/146290.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国庆day2---select实现服务器并发

select.c&#xff1a; #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)#define IP "192.168.1.3" #define PORT 8888int main(int argc, const char *argv[]) {//创建报式套接字socketi…

3. 文档操作

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

渐变色毛玻璃形态卡悬停效果

效果展示 页面结构组成 从上述的效果展示可以看出&#xff0c;页面的组成部分主要包含这几个部分&#xff1a; 渐变色的底层方块毛玻璃的内容层内容层上的两个小方块 CSS 知识点 transformlinear-gradient 实现页面结构布局 <div class"box"><span>…

竞赛 大数据疫情分析及可视化系统

文章目录 0 前言2 开发简介3 数据集4 实现技术4.1 系统架构4.2 开发环境4.3 疫情地图4.3.1 填充图(Choropleth maps)4.3.2 气泡图 4.4 全国疫情实时追踪4.6 其他页面 5 关键代码最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 大数据疫…

笔记本电脑查询连接wifi密码

笔记本电脑查询连接wifi密码 1、背景2、环境3、实操3.1、已连接wifi查看密码3.2、之前连接过的wifi密码查看 1、背景 在日常使用过程中遇到两个使用场景。网络管理员跳过一下步骤&#xff0c;针对wifi使用人员。 1、刚到一个新环境中需要连接wifi的场景 2、在一个场所连接过一…

.Net Core后端架构实战【介入IOC控制反转】

引言 Inversion of Control,简称IOC,即控制反转。记得当初刚实习的时候公司的带我的人和我提到过IOC这个概念,当初完全不知道是 啥东西。后来有幸写了半年Java,SpringBoot里面业务开发随处可见IOC。再后来我写.Net Core用到的第一个框架Blog.Core项目,它里 面IRepository与R…

MATLAB中d2d函数用法

目录 语法 说明 示例 重新采样离散时间模型 重新采样已识别的离散时间模型 d2d函数的功能是重新采样离散时间模型。 语法 sys1 d2d(sys, Ts) sys1 d2d(sys, Ts, method) sys1 d2d(sys, Ts, opts) 说明 sys1 d2d(sys, Ts)将离散时间动态系统模型 sys 重新采样&#…

集合-List集合

系列文章目录 1.集合-Collection-CSDN博客​​​​​​ 2.集合-List集合-CSDN博客 文章目录 目录 系列文章目录 文章目录 前言 一 . 什么是List? 二 . List集合的特点 三 . 常用方法 1.void add(int index, E element): 将指定的元素插入到列表的指定位置。 2.E remove(int in…

StarRocks数据导入

1、相关环境 Flink作为当前流行的流式计算框架&#xff0c;在对接StarRocks时&#xff0c;若直接使用JDBC的方式"流式"写入数据&#xff0c;对StarRocks是不友好的&#xff0c;StarRocks作为一款MVCC的数据库&#xff0c;其导入的核心思想还是"攒微批降频率&qu…

ChatGPT App迎来重大更新;人工智能应用于应对气候变化

&#x1f989; AI新闻 &#x1f680; ChatGPT App迎来重大更新&#xff1a;增加多模态交互方式 摘要&#xff1a;OpenAI最近宣布了ChatGPT App的重大更新&#xff0c;新版的ChatGPT增加了多模态交互方式&#xff0c;用户可以向AI展示正在谈论的内容&#xff0c;比如拍照并询问…

Linux学习[21]账号与群组1---linux中/etc/passwd与/etc/shadow字段说明

文章目录 前言1. passwd字段说明2. shadow字段说明总结 前言 修改树莓派某个用户的权限到管理员权限的时候&#xff0c;涉及到了对/etc/passwd文件的修改&#xff0c;其中的字段具体含义当时也是模棱两可的&#xff0c;最近看了看相关书籍之后&#xff0c;这里做一个说明。 同…

零基础Linux_10(进程)进程终止(main函数的返回值)+进程等待

目录 1. 进程终止 1.1 main函数的返回值 1.2 进程退出码和错误码 1.3 进程终止的常见方法 2. 进程等待 2.1 进程等待的原因 2.2 wait 函数 2.3 waitpid 函数 2.4 int* status参数 2.5 int options非阻塞等待 本篇完。 1. 进程终止 进程终止指的就是程序执行结束了&…

基于树莓派CM4制作img系统镜像批量制作TF卡

文章目录 前言1. 环境与工具2. 制作镜像3. 烧录镜像4. 总结 前言 树莓派烧录完系统做定制化配置比较费时间。在面对大批量的树莓派要配置&#xff0c;那时间成本是非常巨大的。第一次配置完可以说是摸着石头过河&#xff0c;但是会弄了以后再配置&#xff0c;都是一些重复性操…

MYSQL8解压版 windows 主从部署步骤及配置(包含配置文件,教程文件,免积分下载)

MYSQL8解压版 windows 主从部署步骤及配置 一.安装MSYQL 这里只讲大概,详细步骤、my.ini文件、安装包等会在页尾文件中(正常情况按首个mysql安装,只是名字有区别) 1.主库my.ini配置 [mysqld] #典型的值是5-6GB(8GB内存)&#xff0c;8-11GB(16GB内存), 20-25GB(32GB内存)&…

【CVPR 2023】DSVT: Dynamic Sparse Voxel Transformer with Rotated Sets

文章目录 开场白效果意图 重点VoxelNet: End-to-End Learning for Point Cloud Based 3D Object DetectionX-Axis DSVT LayerY-Axis DSVT Layer Dynamic Sparse Window AttentionDynamic set partitionRotated set attention for intra-window feature propagation.Hybrid wind…

Leetcode242. 有效的字母异位词

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 解题思路&#…

(二) gitblit用户使用教程

(一)gitblit安装教程 (二) gitblit用户使用教程 (三) gitblit管理员手册 目录 网页访问git客户端设置推送错误配置查看当前配置 日常使用仓库分组my profile修改上传代码简洁 网页访问 点击Advanced... 点击Accept the Risk and Contiue 初始用户名和密码都是admin,点击login…

树莓派CM4开启I2C与UART串口登录同时serial0映射到ttyS0 开启多串口

文章目录 前言1. 树莓派开启I2C与UART串口登录2. 开启多串口总结&#xff1a; 前言 最近用CM4的时候使用到了I2C以及多个UART的情况。 同时配置端口映射也存在部分问题。 这里集中记录一下。 1. 树莓派开启I2C与UART串口登录 输入指令sudo raspi-config 跳转到如下界面&#…

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

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

系统接口响应信息通用加密设计

设计目的 出于对一些敏感信息的安全性考虑&#xff0c;接口的响应信息需要进行加密&#xff0c;避免明文传输 使用场景 本系统前端响应信息加密 第三方系统响应信息加密 功能设计思路 配置模式加密 使用场景&#xff1a;本系统前端响应信息加密 在nacos中配置需要加密的…