Skip to content

Fetch

[TOC]

索引

Fetch

方法

  • window.fetch()(url, options?),用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。

Response

属性

方法

Fetch

方法

fetch()@

window.fetch()(url, options?),用于发起网络请求的现代 API,基于 Promise 设计,取代了传统的 XMLHttpRequest。

  • urlstring | 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 使用)。
  • 返回:

  • resultResponse,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 对象。
  • 特性:

    1. 错误处理

      • HTTP 错误状态码fetch 不会因 HTTP 错误状态码(如 404, 500)而拒绝 Promise,需手动检查 response.ok
      js
      fetch(url)
        .then(response => {
          if (!response.ok) throw new Error(`HTTP 错误:${response.status}`);
          return response.json();
        });
      • 网络错误:如请求无法到达服务器,Promise 会被拒绝。
    2. CORS 限制

      • 跨域请求需服务器设置 Access-Control-Allow-Origin 响应头。
      • 非简单请求(如 POST 带非标准头)会触发预检请求(Preflight)。
    3. 兼容性:所有现代浏览器均支持 fetch,但旧版浏览器(如 IE)需使用 Polyfill(如 whatwg-fetch)。

  • 示例:

    1. 基本使用-GET

      js
      // 字符串形式
      fetch('https://api.example.com/data');
      
      // Request 对象形式
      const request = new Request('https://api.example.com/data', { method: 'GET' });
      fetch(request);
    2. 基本使用-POST

      js
      fetch('https://api.example.com/data', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer xyz'
        },
        body: JSON.stringify({ key: 'value' }),
        credentials: 'include',
        mode: 'cors'
      });
    3. 链式处理示例

      js
      fetch('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));
    4. 完整示例:考虑各种边界判断

      js
      async 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');
    5. 取消请求:使用 AbortController 中止正在进行的请求

      js
      const 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();
    6. 上传文件:通过 FormData 发送文件。

      js
      const formData = new FormData();
      formData.append('file', fileInput.files[0]);
      
      fetch('https://api.example.com/upload', {
        method: 'POST',
        body: formData
      });
    7. 处理流数据:逐步读取大文件或流。

      readableStream.getReader()(options?)创建一个读取器并将流锁定于其上。一旦流被锁定,其他读取器将不能读取它,直到它被释放。

      js
      fetch('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@【

response.ok

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

status【

response.status

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

statusText【

response.statusText

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

headers@【

response.headers

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

body@【

response.body

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

方法

json()@

response.json()(),读取响应体并将其解析为 JSON

  • 返回:

  • promisePromise<Object>,返回的 Promise 的最终状态取决于响应体的内容:

    • 解析成功(Fulfilled)

      条件:响应体是有效的 JSON 字符串

      结果:Promise 解析为一个由 JSON 反序列化得到的对象或数组。

    • 解析失败 (Rejected)

      条件:响应体是无效的 JSON 字符串(即使是空字符串 ""undefined 也会导致失败)。

      结果:Promise 被拒绝,并抛出一个 SyntaxError 异常。

基本示例

  1. 结合 fetch 的典型用法

    js
    fetch('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);
      }
    }

核心特性

  1. 响应流只能被读取一次

    Response 的响应体是一个只能被使用一次的流。这意味着你只能调用 一个 body 消费方法(如 .json(), .text(), .blob() 等)一次。如果你已经调用了 response.json(),你就不能再调用 response.text() 来读取同一个响应体。

    错误示例

    js
    fetch('https://api.example.com/data')
      .then(response => {
        response.json().then(data => { /* ... */ }); // 第一次读取
        response.text().then(text => { /* ... */ }); // 错误!流已被锁定/读取,此行会报错
      });

    解决方案:使用 response.clone()

    如果你想用多种方式处理同一个响应,你必须先克隆它。

    js
    fetch('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));
      });
  2. 错误处理至关重要

    由于 .json() 在遇到无效 JSON 时会抛出异常,因此必须使用 .catch()try...catch 来优雅地处理这种错误。否则,错误会导致程序中断或产生难以追踪的 bug。

    最佳实践:在 fetch 链中处理错误

    js
    fetch('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);
      });
  3. 检查 Content-Type(可选但推荐)

    虽然 response.json() 会尝试解析任何响应体,但一个设计良好的 API 应该在响应头中设置正确的 Content-Type: application/json。你可以在解析前检查这个头信息,以避免不必要的解析尝试和潜在的失败。

    js
    fetch('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 编码的字符串

  • 返回:

  • promisePromise<string>,返回的 Promise 的最终状态取决于响应体的内容:

    • 解析成功(Fulfilled)

      条件:响应体流被成功读取和解码。

      结果:Promise 解析为一个字符串(String)。这个字符串包含了响应体的完整内容,无论其原本是什么格式(JSON, HTML, XML, CSV, 纯文本等)。

    • 解析失败 (Rejected)

      条件极其罕见。通常只发生在网络错误导致流无法读取,或者响应体本身损坏的情况下。内容本身不是有效的文本并不会导致拒绝

      结果:Promise 被拒绝,并抛出一个异常(通常是 TypeErrorNetworkError)。

基本示例

  1. 结合 fetch 的典型用法

    js
    fetch('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);
      }
    }

核心特性

  1. 响应流只能被读取一次(与 .json() 相同)

  2. 对比 json():宽容性是其核心特点

    这是 text()json() 最根本的区别。

    • json() 要求内容严格符合 JSON 规范,否则会抛出 SyntaxError
    • text() 只是简单地将接收到的字节转换为字符串,不做任何有效性校验
  3. UTF-8 编码

    text() 方法默认使用 UTF-8 编码来解码响应字节流。

    • 如果服务器使用其他编码(虽然在现代 Web 开发中非常罕见),解码结果可能是错误的(乱码)。
    • 服务器通常会在 Content-Type 头中指定编码(如 Content-Type: text/html; charset=ISO-8859-1),但 text() 方法主要依赖 UTF-8。

blob()【

response.blob()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

arrayBuffer()【

response.arrayBuffer()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

fromData()【

response.fromData()()

  • :``,

  • :``,

  • :``,

  • 返回:

  • :``,

基本示例

  1. ****:

    js

核心特性

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js

进阶示例

  1. ****:

    js
  2. ****:

    js
  3. ****:

    js