克隆 Response 对象的主要方式是使用 clone()方法,这个方法会创建一个一模一样的副本,不 会覆盖任何值。这样不会将任何请求的请求体标记为已使用:
有响应体的 Response 对象只能读取一次。(不包含响应体的 Response 对象不受此限制。)比如:
let r = new Response('foobar');
r.text().then(console.log); // foobar
r.text().then(console.log);
// TypeError: Failed to execute 'text' on 'Response': body stream is locked
要多次读取包含响应体的同一个 Response 对象,必须在第一次读取前调用 clone():
let r = new
Response('foobar');
r.clone().text().then(console.log); // foobar
r.clone().text().then(console.log); // foobar
r.text().then(console.log); // foobar
此外,通过创建带有原始响应体的 Response 实例,可以执行伪克隆操作。关键是这样不会把第一 个 Response 实例标记为已读,而是会在两个响应之间共享:
let r1 = new Response('foobar');
let r2 = new Response(r1.body);
console.log(r1.bodyUsed); // false
console.log(r2.bodyUsed); // false
r2.text().then(console.log); // foobar
r1.text().then(console.log);
// TypeError: Failed to execute 'text' on 'Response': body stream is locked
Request、Response及Body混入
let r1 = new Response('foobar'); let r2 = r1.clone();
console.log(r1.bodyUsed); // false
console.log(r2.bodyUsed); // false
如果响应对象的 bodyUsed 属性为 true(即响应体已被读取),则不能再创建这个对象的副本。在 响应体被读取之后再克隆会导致抛出 TypeError。
let r = new Response('foobar'); r.clone();
// 没有错误
r.text(); // 设置bodyUsed为true
r.clone();
// TypeError: Failed to execute 'clone' on 'Response': Response body is
already used
Request 和 Response 都使用了 Fetch API 的 Body 混入,以实现两者承担有效载荷的能力。这个 混入为两个类型提供了只读的 body 属性(实现为 ReadableStream)、只读的 bodyUsed 布尔值(表 示 body 流是否已读)和一组方法,用于从流中读取内容并将结果转换为某种 JavaScript 对象类型。
通常,将 Request 和 Response 主体作为流来使用主要有两个原因。一个原因是有效载荷的大小 可能会导致网络延迟,另一个原因是流 API 本身在处理有效载荷方面是有优势的。除此之外,最好是一
Body 混入提供了 5 个方法,用于将 ReadableStream 转存到缓冲区的内存里,将缓冲区转换为某
种 JavaScript 对象类型,以及通过期约来产生结果。在解决之前,期约会等待主体流报告完成及缓冲被 解析。这意味着客户端必须等待响应的资源完全加载才能访问其内容。
1. Body.text()
Body.text()方法返回期约,解决为将缓冲区转存得到的 UTF-8 格式字符串。下面的代码展示了
在 Response 对象上使用 Body.text():
fetch('https://foo.com')
.then((response) => response.text())
.then(console.log);
// <!doctype html><html lang="en">
// <head>
// <meta charset="utf-8">
// ...
以下代码展示了在 Request 对象上使用 Body.text(): let request = new Request(‘https://foo.com’,
request.text()
.then(console.log);
// barbazqux
{ method: 'POST', body: 'barbazqux' });
Body.json()
Body.json()方法返回期约,解决为将缓冲区转存得到的 JSON。下面的代码展示了在 Response
对象上使用 Body.json():
fetch('https://foo.com/foo.json')
.then((response) => response.json())
.then(console.log);
// {"foo": "bar"}
以下代码展示了在 Request 对象上使用 Body.json(): let request = new Request(‘https://foo.com’,
request.json()
.then(console.log);
// {bar: 'baz'}
{ method:'POST', body: JSON.stringify({ bar: 'baz' }) });
Body.formData()
浏览器可以将 FormData 对象序列化/反序列化为主体。例如,下面这个 FormData 实例:
let myFormData = new FormData();
myFormData.append('foo', 'bar');
在通过 HTTP 传送时,WebKit 浏览器会将其序列化为下列内容:
------WebKitFormBoundarydR9Q2kOzE6nbN7eR
Content-Disposition: form-data; name="foo"
Body.formData()方法返回期约,解决为将缓冲区转存得到的 FormData 实例。下面的代码展示 了在 Response 对象上使用 Body.formData():
fetch('https://foo.com/form-data')
.then((response) => response.formData())
.then((formData) => console.log(formData.get('foo'));
// bar
以下代码展示了在 Request 对象上使用 Body.formData(): let myFormData = new FormData();
myFormData.append('foo', 'bar');
let request = new Request('https://foo.com',
request.formData()
.then((formData) => console.log(formData.get('foo'));
// bar