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 ...
随机推荐
- 2.0 vue循环和方法调用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- linux篇-rpm包安装mysql数据库
3.1上传以下两个rpm包到服务器上 MySQL-server-5.6.27-1.el6.x86_64.rpm MySQL-client-5.6.27-1.el6.x86_64.rpm 3.2卸载一个 ...
- Dockerfile 使用 SSH
如果在书写 Dockerfile 时,有些命令需要使用到 SSH 连接,比如从私有仓库下载文件等,那么我们应该怎么做呢? Dockerfile 使用 SSH Dockerfile 文件配置 为了使得 ...
- Spring IOC 常用注解与使用
@Component 注解@component代表spring ioc 会把这个类扫描生成Bean实例 @Component public class Role{ @Value("1&quo ...
- django框架6
内容概要 神奇的双下划线查询 外键字段的创建 外键字段操作 多表查询 基于对象的跨表查询 基于双下划线的跨表查询 双下线查询扩展 如何查看SQL语句 内容详情 神奇的双下划线查询 1.查询年龄大于20 ...
- Linux查看日志文件写入速度的4种方法
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 有时,我们需要查看某个文件的增长速度,如日志文件,以此来感受系统的负载情况,因为一般情况下,日志写入越快,说明系统 ...
- C#中常用的目录|文件|路径信息操作
更新记录 本文迁移自Panda666原博客,原发布时间:2021年5月16日. 说明 .NET的类库API设计的非常优秀,再加上文档docs.com写的非常优秀,写代码给人一种十分优雅的感觉. 获得当 ...
- php 正则获取字符串中的汉字(去除字符串中除汉字外的所有字符)
preg_match_all('/[\x{4e00}-\x{9fff}]+/u', $list[$i]['iparr'], $matches); $list[$i]['iparr'] = join(' ...
- LayUI+SSM实现一个简单的后台管理系统
该后台管理系统是用于管理视频网站数据的,目前分5个菜单项,这篇博客主要讲述[影片管理]的具体功能和实现 后台代码结构和[影片管理]的界面如下图 该界面分为上下2部分,[搜索条件]和[影片列表],2部分 ...
- java+mybatis实现一个简单的银行系统,实现存取款与账户查询
先创建数据库和表,使用的是MySQL数据库. create database mybatis; use mybatis; CREATE TABLE `accountdo` ( `id` varchar ...
