当前位置: 首页 > news >正文

fetch 在实际项目中的思考

fetch 在实际项目中的思考

随着 fetch 的出现,可以让我们不在需要在项目中导入一些三方库来发送 http 请求。虽然浏览器中早已存在 XMLHttpRequest,但是由于它的写法比较繁琐,我们在使用的通常都是导入一些依赖库来更方便的使用它,比如 jquery 的 $.ajax()、angular 的 $http,以及最常用的 axios。但是 fetch 在实际项目中真的好用吗?

虽然我们确实可以通过 fetch 更容易的操作一些底层的操作,但是在实际项目中使用抽象的、简便的方法其实真的会比直接操作底层 API 会更省力。

错误处理

我们在学习 fetch 的基础写法会发现,它看起来非常像我们常用的依赖库的写法:

// 比如 axios 的写法import axios from "axios";axios.get("http://localhost:3000/api").then((result) => console.log("success:", result)).catch((error) => console.log("error:", error));

通过 fetch 改写可以写成如下:

fetch("http://localhost:3000/api").then((response) => response.json()).then((result) => console.log("success:", result)).catch((error) => console.log("error:", error));

看起来 fetch 只是多了一行将响应流解析成 JSON 格式的代码,看起来问题不是很大。

但是我们在认真看一下,或者实际上调用一下就会发现,它们是不一样的,前面提到的多种三方库在处理错误状态码(比如 404、500 这些)的时候都会当成是一个错误。但是 fetch 只会在网络异常(ip 解析异常、服务无法访问或者 cors)的时候才会拒绝这个 Promise,之后在 catch 中捕获。

这也就意味在上面的代码中,如果我们的响应状态码是 404,fetch 代码段还是会打印 success。如果我们想在服务端响应异常的时候返回一个拒绝状态,就需要额外添加一些代码:

fetch("http://localhost:3000/api").then((response) => {return response.json().then((data) => {if (response.ok) {return data;} else {return Promise.reject({ status: response.status, data });}});}).then((result) => console.log("success:", result)).catch((error) => console.log("error:", error));

ok 的值只在响应码处于 200 - 299 的范围内才返回 true

可能很多人会觉得这没什么,即便从服务端返回的是 404 这样的状态码,也是从服务端获取的数据,说明服务端确实成功响应了。这其实是一种观点,没有什么对错之分,只不过在我看来服务端返回的错误响应还是应该认为是一种异常,但是我们没办法修改 fetch 的规范,我们只是应该存在一种更好的抽象去表示。

POST 请求

另一种常用的场景就是发送 POST 请求,当我们使用 axios 去发送,只需要简单的一行:

axios.post('http://localhost:3000/user', {name: 'leo'
})

但是在 fetch 中,我们却需要使用定义一堆东西,简单的设置 method、body 并不能成功请求,比如:

fetch("http://localhost:3000/user", {method: "POST",body: {name: "leo",},
})

这种简单写法发送给服务端的数据是异常的([object Object])。fetch 的 API 是非常显式的,对于发送的是 JSON 数据,我们必须把这个数据转成字符串,并添加 Content-Type: application/json 头来告诉服务端这个 payload 是 JSON,否则服务端会认为它是一个字符串。

改写如下可以正常使用:

fetch("http://localhost:3000/user", {method: "POST",headers: {'Content-Type': 'application/json'}body: JSON.stringify({name: "leo",}),
})

假设我们有非常多类似的请求,那就要重复写这些配置。

fetch 默认设置

如前面所说,fetch 是一种非常显式的 API,如果我们不主动设置,就不能拿到任何东西。在实际项目中,可能存在以下问题:

  1. fetch 默认是不会发送 cookie 的,如果我们的项目中依赖 cookie 来做验证就需要手动进行配置。
  2. 需要手动设置 ‘Accept: application/json’ 表明客户端可以处理 JSON 数据。
  3. fetch 默认是不支持 cors 的

所以我们在 fetch 请求中都需要设置如下:

fetch(url, {credentials: "include",mode: "cors",headers: {Accept: "application/json",},
});

看起来多加点配置也没什么,但是如果我们的项目中每个请求都需要添加这些呢?fetch 并没有提供可以修改默认的方法。

axios 提供了这种修改默认配置的方法,非常简便:

axios.defaults.baseURL = 'http://localhost:3000';
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.headers.post['Content-Type'] = 'application/json';

axios 的目标是为了能简单的调用 api 发送请求。而 fetch 的目标更远大,并不是很适合我们目前的项目。

总结

如果我们不想要导入三方库来发送请求,意味着我们就不能通过下面这一行代码实现:

function addUser(details) {return axios.post('http://localhost:3000/user', details);
}

而是需要封装一个这样的方法:

function addUser(details) {return fetch('http://localhost:3000/user', {mode: 'cors',method: 'POST',credentials: 'include',body: JSON.stringify(details),headers: {'Content-Type': 'application/json','Accept': 'application/json',}}).then(response => {return response.json().then(data => {if (response.ok) {return data;} else {return Promise.reject({status: response.status, data});}});});
}

这个一看就知道在项目中是不应该存在大量这样的重复代码,我们可能需要将更多的场景考虑进来,然后进行一个封装。

那么当我们有另一个项目也需要这个封装函数的时候,是不是又要去修改、优化,来让这些 api 变得更简便、
适用。但是在这个过程中我们是不是又创建了一个发送请求的库,而不是直接使用 fetch 这个 api 呢?

当然,本文并不是在否认 fetch 是一个无用的设计,fetch 的底层设计非常好,比起 XMLHttpRequest,它能让我们对请求进行更细的控制。只不过在日常项目中这种底层 api 不是非常适用,直接使用封装好的工具可能是更好的选择。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 2024华为OD机试真题- 求字符串中所有整数的最小和-(C++/Python)-C卷D卷-100分
  • 中国联通在国外最大的综合电信服务枢纽
  • 【算法模板】数据结构:单调栈
  • vue2和vue3项目使用signalr插件,前后端如何配合的
  • 大语言模型有什么用途?
  • 计算机网络17——IM聊天系统——客户端核心处理类框架搭建
  • XV6——锁与并发
  • AI技术在招聘数据分析洞察中的作用
  • haproxy总结与实验
  • sgetrf M N is 103040 时报错,这是个bug么 lapack and Openblas the same,修复备忘
  • 网站证书过期导致WordPress后台无法登录问题解决,页面样式丢失
  • EMQX Platform Snowflake:构建可再生分布式能源的智慧未来
  • 了解LVS,配置LVS
  • 刚刚,模糊测试平台SFuzz受到行业认可
  • 在 SOCKS 和 HTTP 代理之间如何选择?
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 11111111
  • 2017前端实习生面试总结
  • 2019年如何成为全栈工程师?
  • git 常用命令
  • Java 网络编程(2):UDP 的使用
  • java第三方包学习之lombok
  • Material Design
  • Node项目之评分系统(二)- 数据库设计
  • spring + angular 实现导出excel
  • 免费小说阅读小程序
  • 普通函数和构造函数的区别
  • 探索 JS 中的模块化
  • 移动端唤起键盘时取消position:fixed定位
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • ​iOS实时查看App运行日志
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (10)ATF MMU转换表
  • (C#)获取字符编码的类
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (安卓)跳转应用市场APP详情页的方式
  • (第61天)多租户架构(CDB/PDB)
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二开)Flink 修改源码拓展 SQL 语法
  • (分布式缓存)Redis哨兵
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net core 6 redis操作类
  • .Net Core和.Net Standard直观理解
  • ??在JSP中,java和JavaScript如何交互?
  • [ 网络通信基础 ]——网络的传输介质(双绞线,光纤,标准,线序)
  • [AIGC] 开源流程引擎哪个好,如何选型?
  • [Android] Upload package to device fails #2720
  • [C#]猫叫人醒老鼠跑 C#的委托及事件
  • [C#7] 1.Tuples(元组)
  • [Datawhale AI夏令营 2024 第四期] 从零入门大模型微调之旅的总结
  • [GICv3] 3. 物理中断处理(Physical Interrupt Handling)