js Fetch返回数据res.json()报错问题
前言
一直以来在简单的场景中经常使用fetch代替第三方请求库, fetch是JavaScript的原生函数, 简单、高效、快速、稳定、可定制等等诸多优点。一直也是用着很是舒服,直到有一天它竟然报错了。
什么是Fetch?
官方: Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。
还原现场
因为业务需求简单,这里只封装了get和post方法, 并且后端数据都是已默认的json格式返回
const http = {
apiBaseUrl: config.apiBaseUrl,
get: function (url) {
return new Promise((resolve, reject) => {
fetch(this.apiBaseUrl + url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
}).then(res => res.json()).then(res => {
resolve(res);
}).catch(e => {
console.error("请求失败了,详细信息:" + JSON.stringify(e));
reject(e);
});
})
},
post: function (url, body) {
return new Promise((resolve, reject) => {
fetch(this.apiBaseUrl + url, {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}, body: JSON.stringify(body)
}).then(res => res.json()).then(res => {
resolve(res);
}).catch(e => {
console.error("请求失败了,详细信息:" + JSON.stringify(e));
reject(e);
})
})
}
}
这样的封装貌似也没什么问题 。
后端没有做统一的返回数据格式约定, 直接使用.net中的ActionResult结构返回, .net封装的应该都是很好用的
/// <summary>
/// 模拟处理数据
/// </summary>
/// <returns></returns>
[HttpPost("handle-data")]
public ActionResult HandleData(string mockData)
{
// 业务逻辑
// ......
// 处理完成,直接告诉浏览器我Ok了, 状态200
return Ok();
}
此时前端在处理完成后, 控制台面板中 Network 中也显示post成功返回200了, 但是在 Console 中却有一条红色报错信息
请求失败了,详细信息:{}

看到报错位置竟然是post中的catch, 可明明在Network中看到返回200了啊, 稍作镇静之后就意识到应该就是返回时数据处理报错了, 在resolve(res)上面打印也没走这个逻辑, 那就是 上一层 .then(res=> res.json()有问题。
// 将.then(res=> res.json()) 替换成下面
.then(res => {
console.log(res.json());
return res.json();
})
这样写同样报错

可以看到时解析json报错了, 嗯, 因为我们就是没有返回任何数据, 解析自然会报错!
既然没有值Json解析报错, 那解决办法自然就得加一层判断了(也可以让后端必须返回一个Json, 简单粗暴, 哈哈! ) , 思路是先读取值然后判断是否为空.
但是打印res时
// 将.then(res=> res.json()) 替换成下面
.then(res => {
console.log(res);
let arrayBuffer = res.json();
let json = res.json();
return res.json();
})
body: ReadableStream
locked: true
[[Prototype]]: ReadableStream
bodyUsed: true
headers: Headers
[[Prototype]]: Headers
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "'http://localhost:5069/api/handle-data"
[[Prototype]]: Response
而且还有一条报错信息
Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream already read
body stream already read说明流只能读取一次,
body是一个ReadableStream数据流,必须先读取流才能看到数据, 那就看一下是否还能转换成其他格式的数据.
查找MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch#body
Body 类定义了以下方法(这些方法都被
Request和Response所实现)以获取 body 内容。这些方法都会返回一个被解析后的 Promise 对象和数据。
可知有5种数据格式,因为json和text可使用js原生方法JSON.parse/JSON.stringify相互转换, 那就直接选用.text()转成字符串判断即可.
// 将.then(res=> res.json()) 替换成下面
.then(res => {
let data = res.text();//转成字符串判断
return data.then(r => {
if (r.length === 0) return null;
else return JSON.parse(r);
})
})
验证结果正确, 一切又回到了正常。
简单封装fetch 获取json或空数据
let checkStatus = res => {
if (res.status >= 200 && res.status < 300) return res;
else {
let err = new Error(res.statusText);
err.response = res;
throw err;
}
}
let parseJson = res => {
let data = res.text();
return data.then(r => {
if (r.length === 0) return null;
else return JSON.parse(r);
})
}
const http = {
apiBaseUrl: config.apiBaseUrl,
get: function (url) {
return new Promise((resolve, reject) => {
fetch(this.apiBaseUrl + url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
}).then(checkStatus).then(parseJson).then(res => {
resolve(res);
}).catch(e => {
console.error("请求失败了,详细信息:" + JSON.stringify(e));
reject(e);
});
})
},
post: function (url, body) {
return new Promise((resolve, reject) => {
fetch(this.apiBaseUrl + url, {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}, body: JSON.stringify(body)
}).then(checkStatus).then(parseJson).then(res => {
resolve(res);
}).catch(e => {
console.error("请求失败了,详细信息:" + JSON.stringify(e));
reject(e);
})
})
}
}
嗯 , 前端能处理的问题就不麻烦后端了
总结
fetch返回的是数据流, 最终是什么格式数据需要我们自己判断使用, arrayBuffer/blob/formData/json/text 这些格式都有其使用场景, 前端er不要将思维只限定在了json哦。
作者:wwmin
出处:https://www.cnblogs.com/cnwwm
联系:wwei.min@163.com 微信:w_wmin
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如有问题或建议,请多多赐教,非常感谢。
js Fetch返回数据res.json()报错问题的更多相关文章
- Hibernate 连接数据库,数据库返回数据超过限制报错
1.packet for query is too large 1024 >. you can change this value on the server mysql max_allowed ...
- 02 - Unit01:服务器返回数据的json处理+搭建项目环境
服务器返回数据的json处理+搭建项目环境 服务器返回数据的json处理 springMVC JSP响应流程 请求 -->DispatcherServlet -->HandlerMappi ...
- 对Ajax返回的json数据做处理报错
这个错误出现的原因是我再返回数据为json时,我页面的Ajax没有指定dataType: 'json'
- spring jpa 实体互相引用返回restful数据循环引用报错的问题
spring jpa 实体互相引用返回restful数据循环引用报错的问题 Java实体里两个对象有关联关系,互相引用,比如,在一对多的关联关系里 Problem对象,引用了标签列表ProblemLa ...
- Springboot实体类转JSON报错Could not find acceptable representation & 设置访问项目根路径的默认欢迎页面
=================实体类转JSON报错的解决办法============= 之前在springmvc的时候也报过这个错,原因以及springmvc中解决办法参考:https://www ...
- fasterxml.jackson 将对象转换为json报错处理
最近在做查询的数据遇到如下报错: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found ...
- Newtonsoft.Json报错:未能加载文件或程序集"..."或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配
Newtonsoft.Json报错:未能加载文件或程序集"..."或它的某一个依赖项.找到的程序集清单定义与程序集引用不匹配. □ 背景分析 在帮助类库中使用了Newtonso ...
- golang解析json报错:invalid character '\x00' after top-level value
golang解析json报错:invalid character '\x00' after top-level value 手动复制字符串:{"files":["c:/t ...
- vue.js 中使用(...)运算符报错的解决方法
vue.js 中使用(...)运算符报错的解决方法 Syntax Error:Unexpected token(XX:X) }, computed:{ ...mapGetters([ 'pageSiz ...
随机推荐
- 前后端分离,SpringBoot如何实现验证码操作
验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的. SpringBoot版本 本文基于的Spring Boot的 ...
- 152-技巧-Power Query 快速合并文件夹中表格之自定义函数 TableXlsxCsv
152-技巧-Power Query 快速合并文件夹中表格之自定义函数 TableXlsxCsv 附件下载地址:https://jiaopengzi.com/2602.html 一.背景 在我们使用 ...
- 记一次IIS网站启动不了的问题排查
今天清理了下机器中的IIS网站,将很久不用的网站都删除. 因为需要删除的比较多,正在使用的很少,就将网站全部删除了,然后准备重新添加需要用的. 在添加了网站后,点击启动按钮,发现网站启动不了,因为网站 ...
- Jackson多态序列化
场景 做一个消息中心,专门负责发送消息.消息分为几种渠道,包括手机通知(Push).短信(SMS).邮件(Email),Websocket等渠道. 我定义了一个基类MessageRequest用来接收 ...
- 接口测试postman深度挖掘应用③--postman终结篇
上一章节我们介绍了postman的变量测试以及导入数据测试基本上技术性的东西已经差不过了,这篇文章再系统性的介绍一下. 一.下载 官网:https://www.postman.com 1.选择需要下载 ...
- torch.nn.MSELoss()函数解读
转载自:https://www.cnblogs.com/tingtin/p/13902325.html
- SQL的语法
SQL的语法 SQL通用语法 SQL语句可以单行或多行书写,以分号(";")结尾. SQL语句可以使用空格或缩进增强可读性. MySQL数据库的SQL语句不区分大小写(建议关键字大 ...
- 论文阅读 dyngraph2vec: Capturing Network Dynamics using Dynamic Graph Representation Learning
6 dyngraph2vec: Capturing Network Dynamics using Dynamic Graph Representation Learning207 link:https ...
- DevOps落地实践点滴和踩坑记录-(1)
记录初衷 本人一直在从事企业内DevOps落地实践的工作,走了不少弯路,也努力在想办法解决面临的问题,期间也经历过不少人和事情,最近突然有想法把经历过的,不管好的不好的都记录下来,分享给和我一样的一线 ...
- Git出现“filename too long”错误处理
更新记录 本文迁移自Panda666原博客,原发布时间:2021年5月8日. 怎么肥事? Windows系统下,在Git使用过程中,出现"filename too long"错误提 ...
