Fetch
[TOC]
索引
Fetch
方法:
- window.fetch():
(url, options?)
,用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。
Response
属性:
方法:
- response.json():
()
,读取响应体并将其解析为 JSON。 - response.text():
()
,读取响应体并将其解析为 UTF-8 编码的字符串。 - response.blob():
()
, - response.arrayBuffer():
()
, - response.fromData():
()
,
Fetch
方法
fetch()@
window.fetch():(url, options?)
,用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。
url:
string | Request
,指定请求的目标 URL 或预配置的 Request 实例。options?:
{}
,配置请求的选项对象(如请求方法、请求头、请求体等)。- method?:
GET|POST|PUT|DELETE|PATCH
,默认:GET
,HTTP请求方法。 - headers?:
object | Headers
,请求头信息。 - body?:
string|Blob|FormData
,请求体数据(GET 或 HEAD 请求不能包含 body)。 - mode?:
cors|no-cors|same-origin
,默认:cors
,请求模式 - credentials?:
omit|same-origin|include
,默认:same-origin
,是否发送凭据(cookie)。omit
:不发送。same-origin
:同源发送。include
:始终发送。
- cache?:
default|no-store|no-cache|reload|...
,缓存策略。 - redirect?:
follow|error|manual
,重定向处理方式。follow
:自动跟随error
:报错manual
:手动处理
- signal?:
AbortSignal
,用于取消请求的 AbortSignal 对象(结合 AbortController 使用)。
- method?:
返回:
result:
Response
,Promise 对象,解析为 Response 对象。- 常见属性:
- status:HTTP 状态码(如
200
,404
)。 - statusText:状态描述(如
OK
,Not Found
)。 - headers:响应头信息(可通过
headers.get('Content-Type')
获取)。 - ok:布尔值,表示状态码是否在
200-299
范围内。 - 常见方法:
- json():解析响应体为 JSON 对象。
- text():解析响应体为字符串。
- blob():解析响应体为
Blob
对象。 - formData():解析响应体为
FormData
对象。 - arrayBuffer():解析响应体为
ArrayBuffer
对象。
特性:
错误处理:
- HTTP 错误状态码:
fetch
不会因 HTTP 错误状态码(如404
,500
)而拒绝 Promise,需手动检查response.ok
。
jsfetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP 错误:${response.status}`); return response.json(); });
- 网络错误:如请求无法到达服务器,Promise 会被拒绝。
- HTTP 错误状态码:
CORS 限制:
- 跨域请求需服务器设置
Access-Control-Allow-Origin
响应头。 - 非简单请求(如
POST
带非标准头)会触发预检请求(Preflight)。
- 跨域请求需服务器设置
兼容性:所有现代浏览器均支持
fetch
,但旧版浏览器(如 IE)需使用 Polyfill(如whatwg-fetch
)。
示例:
基本使用-GET
js// 字符串形式 fetch('https://api.example.com/data'); // Request 对象形式 const request = new Request('https://api.example.com/data', { method: 'GET' }); fetch(request);
基本使用-POST
jsfetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer xyz' }, body: JSON.stringify({ key: 'value' }), credentials: 'include', mode: 'cors' });
链式处理示例
jsfetch('https://api.example.com/data') .then(response => { if (!response.ok) throw new Error('请求失败'); return response.json(); }) .then(data => console.log(data)) .catch(error => console.error('错误:', error));
完整示例:考虑各种边界判断
jsasync function fetchData(url) { try { const response = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json' }, credentials: 'include' }); if (!response.ok) throw new Error(`HTTP 错误:${response.status}`); const data = await response.json(); console.log(data); } catch (error) { console.error('请求失败:', error); } } fetchData('https://api.example.com/data');
取消请求:使用 AbortController 中止正在进行的请求
jsconst controller = new AbortController(); const signal = controller.signal; fetch('https://api.example.com/data', { signal }) .then(response => response.json()) .catch(error => { if (error.name === 'AbortError') console.log('请求已取消'); }); // 取消请求 controller.abort();
上传文件:通过 FormData 发送文件。
jsconst formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('https://api.example.com/upload', { method: 'POST', body: formData });
处理流数据:逐步读取大文件或流。
readableStream.getReader():
(options?)
,创建一个读取器并将流锁定于其上。一旦流被锁定,其他读取器将不能读取它,直到它被释放。jsfetch('https://api.example.com/large-file') .then(response => { const reader = response.body.getReader(); return new ReadableStream({ start(controller) { function push() { reader.read().then(({ done, value }) => { if (done) { controller.close(); return; } controller.enqueue(value); push(); }); } push(); } }); }) .then(stream => new Response(stream)) .then(response => response.text()) .then(text => console.log(text));
Response
属性
ok@【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
status【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
statusText【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
headers@【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
body@【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
方法
json()@
response.json():()
,读取响应体并将其解析为 JSON。
返回:
promise:
Promise<Object>
,返回的 Promise 的最终状态取决于响应体的内容:解析成功(Fulfilled):
条件:响应体是有效的 JSON 字符串。
结果:Promise 解析为一个由 JSON 反序列化得到的对象或数组。
解析失败 (Rejected):
条件:响应体是无效的 JSON 字符串(即使是空字符串
""
或undefined
也会导致失败)。结果:Promise 被拒绝,并抛出一个
SyntaxError
异常。
基本示例:
结合 fetch 的典型用法:
jsfetch('https://api.example.com/data') .then(response => response.json()) // 调用 .json() 方法 .then(data => { // 处理解析成功后的数据 console.log(data); }) .catch(error => { // 捕获可能出现的错误 console.error('Error:', error); });
js// 使用 async/await 语法更简洁 async function fetchData() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); // 等待解析完成 console.log(data); } catch (error) { console.error('Error:', error); } }
核心特性:
响应流只能被读取一次:
Response
的响应体是一个只能被使用一次的流。这意味着你只能调用 一个 body 消费方法(如.json()
,.text()
,.blob()
等)一次。如果你已经调用了response.json()
,你就不能再调用response.text()
来读取同一个响应体。错误示例:
jsfetch('https://api.example.com/data') .then(response => { response.json().then(data => { /* ... */ }); // 第一次读取 response.text().then(text => { /* ... */ }); // 错误!流已被锁定/读取,此行会报错 });
解决方案:使用 response.clone()
如果你想用多种方式处理同一个响应,你必须先克隆它。
jsfetch('https://api.example.com/data') .then(response => { const clone1 = response.clone(); // 创建副本 const clone2 = response.clone(); // 创建另一个副本 // 用原始响应解析 JSON response.json().then(data => console.log('JSON:', data)); // 用第一个副本获取文本 clone1.text().then(text => console.log('Text:', text)); // 用第二个副本获取 Blob (虽然不常见) clone2.blob().then(blob => console.log('Blob size:', blob.size)); });
错误处理至关重要:
由于
.json()
在遇到无效 JSON 时会抛出异常,因此必须使用.catch()
或try...catch
来优雅地处理这种错误。否则,错误会导致程序中断或产生难以追踪的 bug。最佳实践:在 fetch 链中处理错误
jsfetch('https://api.example.com/data') .then(response => { // 首先检查 HTTP 状态是否成功 (200-299) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); // 手动抛出错误,会被后面的 .catch 捕获 } return response.json(); // 只有状态正常时才解析 JSON }) .then(data => { // 处理解析成功的数据 console.log(data); }) .catch(error => { // 这里会捕获两种错误: // 1. fetch 本身的网络错误(如无法连接) // 2. 上面手动抛出的 HTTP 状态错误 // 3. response.json() 解析失败的 SyntaxError console.error('Fetch operation failed:', error); });
检查 Content-Type(可选但推荐):
虽然
response.json()
会尝试解析任何响应体,但一个设计良好的 API 应该在响应头中设置正确的Content-Type: application/json
。你可以在解析前检查这个头信息,以避免不必要的解析尝试和潜在的失败。jsfetch('https://api.example.com/data') .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // 检查 Content-Type 头是否包含 'application/json' const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { throw new TypeError("The server didn't send back JSON!"); } return response.json(); }) .then(data => console.log(data)) .catch(error => console.error(error));
text()
response.text():()
,读取响应体并将其解析为 UTF-8 编码的字符串。
返回:
promise:
Promise<string>
,返回的 Promise 的最终状态取决于响应体的内容:解析成功(Fulfilled):
条件:响应体流被成功读取和解码。
结果:Promise 解析为一个字符串(String)。这个字符串包含了响应体的完整内容,无论其原本是什么格式(JSON, HTML, XML, CSV, 纯文本等)。
解析失败 (Rejected):
条件:极其罕见。通常只发生在网络错误导致流无法读取,或者响应体本身损坏的情况下。内容本身不是有效的文本并不会导致拒绝。
结果:Promise 被拒绝,并抛出一个异常(通常是
TypeError
或NetworkError
)。
基本示例:
结合 fetch 的典型用法:
jsfetch('https://example.com/some-text-file.txt') .then(response => response.text()) // 调用 .text() 方法 .then(text => { // 处理成功获取到的文本 console.log(text); document.getElementById('content').innerText = text; // 例如:显示在页面上 }) .catch(error => { // 捕获网络错误或流读取错误 console.error('Error:', error); });
js// 使用 async/await 语法 async function fetchText() { try { const response = await fetch('https://example.com/some-text-file.txt'); const text = await response.text(); // 等待文本读取完成 console.log(text); } catch (error) { console.error('Fetch failed:', error); } }
核心特性:
响应流只能被读取一次(与
.json()
相同)对比
json()
:宽容性是其核心特点:这是
text()
与json()
最根本的区别。json()
要求内容严格符合 JSON 规范,否则会抛出SyntaxError
。text()
只是简单地将接收到的字节转换为字符串,不做任何有效性校验。
UTF-8 编码:
text()
方法默认使用 UTF-8 编码来解码响应字节流。- 如果服务器使用其他编码(虽然在现代 Web 开发中非常罕见),解码结果可能是错误的(乱码)。
- 服务器通常会在
Content-Type
头中指定编码(如Content-Type: text/html; charset=ISO-8859-1
),但text()
方法主要依赖 UTF-8。
blob()【
response.blob():()
,
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
arrayBuffer()【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js
fromData()【
:``,
:``,
:``,
返回:
:``,
基本示例:
****:
js
核心特性:
****:
js****:
js****:
js
进阶示例:
****:
js****:
js****:
js