Fetch请求解析JSON失败转文本报错:响应体流已读取
问题:fetch解析JSON失败后调用text()报错:body stream already read
需求
从服务器获取数据,优先尝试将响应体解析为JSON,解析失败则返回纯文本。
原实现代码
fetch(`/devapi/${url}`, { method: 'GET', headers: new Headers({ Authorization: `Bearer ${localStorage.getItem("token")}`, }), }) .then((res) => res .json() .then((res) => res?.body?.data || res?.body || res) .catch((err) => res.text()) ) .then((val) => console.log(val));
报错信息
Failed to execute 'text' on 'Response': body stream already read
问题根源
Response的body是一次性可读流,调用json()时会把整个流读取并消耗掉,流被读取后就没法再调用text()或其他body解析方法,自然会触发这个报错。
解决方案
方案一:先读文本再尝试解析(推荐)
先把响应体读取成原始文本,再尝试转JSON,失败直接返回文本。全程只读取一次流,性能更好逻辑也清晰。
fetch(`/devapi/${url}`, { method: 'GET', headers: new Headers({ Authorization: `Bearer ${localStorage.getItem("token")}`, }), }) .then(res => res.text()) // 先读文本,只消耗一次流 .then(text => { try { const json = JSON.parse(text); return json?.body?.data || json?.body || json; } catch (err) { // 解析失败返回原文本 return text; } }) .then(val => console.log(val));
方案二:克隆Response对象
通过clone()复制一份Response,分别用原对象和克隆对象执行json、text解析。这种方式会读取两次流,适合特殊场景下使用。
fetch(`/devapi/${url}`, { method: 'GET', headers: new Headers({ Authorization: `Bearer ${localStorage.getItem("token")}`, }), }) .then(res => { const resClone = res.clone(); return res.json() .then(json => json?.body?.data || json?.body || json) .catch(() => resClone.text()); }) .then(val => console.log(val));
内容的提问来源于stack exchange,提问作者Sherif eldeeb
相关产品推荐
相关产品推荐

