fetch api 的 response 对象 body 是单次读取的 readablestream,需用 clone() 创建独立副本才能多次读取;克隆必须在任何读取方法调用前进行,否则报错。

Fetch API 的 Response 对象默认是“单次读取”的——一旦调用 response.json()、response.text() 或 response.blob() 等方法,响应体的 ReadableStream 就会被消耗掉,再次调用会返回空或报错。想多次读取(比如先检查状态再解析 JSON,或同时做日志和业务处理),就得用 response.clone()。
为什么需要 clone?
Response 的 body 是一个底层 ReadableStream,设计上只允许消费一次。这是为了节省内存、避免重复解析和网络资源浪费。但开发中常需“先看一眼再处理”,比如:
- 收到响应后先检查
response.status和response.headers,再决定是否解析 JSON; - 把响应内容同时记录到日志、存入缓存、再交给业务逻辑;
- 在中间件或拦截器中预读响应体用于鉴权或审计。
clone() 的基本用法
response.clone() 返回一个**完全独立的副本**,拥有自己的 stream 和 body,可单独调用读取方法,互不影响:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
fetch('/api/data')
.then(response => {
const cloned = response.clone(); // 克隆一份
// 原 response 用于检查状态
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
// 克隆体用于解析数据
return cloned.json();
})
.then(data => console.log(data));
克隆后仍要分别处理每个副本
克隆只是复制了流的“起点”,每个副本仍需独立调用读取方法,且每个副本也只能读一次:
- 不能对同一个克隆体多次调用
.json(),第二次会返回 Promise rejected(因为 stream 已锁); - 可以对原 response 读
.text(),对 clone 读.json(),只要不交叉重复消费; - 如果想同时获取 text 和 json,必须 clone 两次(或用一次 clone + 多个并发读取)。
例如,同时记录原始文本并解析结构化数据:
fetch('/api/data')
.then(response => {
const clone1 = response.clone();
const clone2 = response.clone();
const rawText = clone1.text(); // 读原始字符串
const jsonData = clone2.json(); // 读解析后的对象
return Promise.all([rawText, jsonData]);
})
.then(([text, data]) => {
console.log('Raw:', text);
console.log('Parsed:', data);
});
注意点和常见陷阱
克隆必须在读取前进行 —— 一旦调用了 response.json() 等方法,原始 stream 就已关闭,再调用 .clone() 会抛出 TypeError("Failed to execute 'clone' on 'Response': Response body is already used")。
- ✅ 正确:先 clone,再读取各副本;
- ❌ 错误:先
response.json(),再response.clone(); - ⚠️ 注意:
response.body是 ReadableStream,直接访问它不会触发消费,但调用.getReader()后若不读完,也可能影响后续 clone(建议优先用高层方法如.json())。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










