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 ...
随机推荐
- 167. Two Sum II - Input array is sorted - LeetCode
Question 167. Two Sum II - Input array is sorted Solution 题目大意:和Two Sum一样,这里给出的数组是有序的 思路:target - nu ...
- Johnson 全源最短路
学这个是为了支持在带负权值的图上跑 Dijkstra. 为了这个我们要考虑把负的权值搞正. 那么先把我们先人已经得到的结论摆出来.我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体 ...
- Kafka 消费者解析
一.消费者相关概念 1.1 消费组&消费者 消费者: 消费者从订阅的主题消费消息,消费消息的偏移量保存在Kafka的名字是__consumer_offsets的主题中 消费者还可以将⾃⼰的偏移 ...
- 前端2CSS
内容概要 form表单 网络请求方式 CSS简介 CSS查找标签之基本选择器(重要) CSS查找标签之组合选择器(重要) 属性选择器 分组与嵌套 伪类选择器 内容详情 form表单 "&qu ...
- ExtJS配置TabPanel可以拖拽Tab标签页
1.环境说明 ExtJS版本:7.4.0.42 Sencha Cmd: v7.5.1.20 开发工具:WebStorm 2022.1.1 PS:如果是老版本的ExtJS,引入Ext.ux.TabReo ...
- powershell命令总结
2021-07-21 初稿 ps命令采用动词-名词的方式命名,不区分大小写.默认当前文件夹为当前路径./.除去-match使用正则表达式匹配外,其他都使用*和?通配符. 速查 管道命令 前一个的输出作 ...
- sap 调用Http 服务
REPORT ZMJ_GETAPI. DATA: LEN TYPE I, "发送报文长度 LEN_STRING TYPE STRING, URL TYPE STRING, "接口地 ...
- zabbix监控mysql主从同步
获取主从复制sql线程和I/O线程状态是否为yes #!/bin/bash HOSTNAME="数据库IP" PORT="端口" USERNAME=" ...
- Flink1.13.1源码解析-Application on yarn(一)
本篇文章讲述 Flink Application On Yarn 提交模式下,从命令提交到 AM 容器创建 1.脚本入口 flink run-application -t yarn-applicati ...
- Nginx开机自启
编写service脚本: vim /usr/lib/systemd/system/nginx.service 将以下内容复制到nginx.service文件中 ps:我的nginx目录是/usr/lo ...