Fetch API:现代化的HTTP请求方式 (Promise-based)

Fetch API:现代化的HTTP请求方式 (Promise-based)

欢迎来到Fetch API讲座

大家好,欢迎来到今天的讲座。今天我们要聊一聊现代前端开发中不可或缺的一个工具——Fetch API。如果你还在用 XMLHttpRequest 或者 jQuery 的 $.ajax,那么是时候升级你的技能了!Fetch API 是一种基于 Promise 的 HTTP 请求方式,它不仅简洁易用,还能让你的代码更加优雅。

为什么选择 Fetch API?

在 Fetch API 出现之前,我们通常使用 XMLHttpRequest 来进行 HTTP 请求。虽然 XMLHttpRequest 功能强大,但它有一个致命的缺点:回调地狱。你可能已经经历过那种嵌套多层回调的痛苦,代码难以维护,调试也变得异常困难。

// XMLHttpRequest 示例
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(JSON.parse(xhr.responseText));
    }
};
xhr.send();

相比之下,Fetch API 使用了 Promise,这意味着你可以通过 .then().catch() 来处理异步操作,避免了回调地狱。更重要的是,Fetch API 的语法更加简洁,易于阅读和理解。

// Fetch API 示例
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Fetch API 的基本用法

1. 发送 GET 请求

最简单的用法就是发送一个 GET 请求。fetch() 函数接受两个参数:

  • 第一个参数是请求的 URL。
  • 第二个参数(可选)是一个配置对象,用于指定请求的类型、头信息等。
// 发送 GET 请求
fetch('https://api.example.com/data')
  .then(response => {
    // 检查响应状态
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json(); // 将响应体解析为 JSON
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

2. 发送 POST 请求

除了 GET 请求,POST 请求也非常常见。我们可以使用 fetch() 的第二个参数来指定请求方法、请求体和其他选项。

// 发送 POST 请求
fetch('https://api.example.com/post', {
  method: 'POST', // 请求方法
  headers: {
    'Content-Type': 'application/json' // 设置请求头
  },
  body: JSON.stringify({ name: 'Qwen', age: 25 }) // 请求体
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

3. 处理不同类型的响应

fetch() 返回的 Response 对象提供了多种方法来处理不同的响应格式。常见的有:

  • response.json():将响应体解析为 JSON。
  • response.text():将响应体解析为纯文本。
  • response.blob():将响应体解析为 Blob 对象,适用于下载文件。
  • response.formData():将响应体解析为 FormData 对象,适用于表单数据。
// 处理不同类型的响应
fetch('https://api.example.com/image')
  .then(response => response.blob()) // 获取图片作为 Blob
  .then(blob => {
    const img = document.createElement('img');
    img.src = URL.createObjectURL(blob);
    document.body.appendChild(img);
  })
  .catch(error => console.error('Error:', error));

Fetch API 的高级用法

1. 超时处理

默认情况下,fetch() 不支持超时机制。如果我们希望在一定时间内没有收到响应时取消请求,可以使用 AbortController 来实现。

// 使用 AbortController 实现超时
const controller = new AbortController();
const signal = controller.signal;

setTimeout(() => {
  controller.abort(); // 如果 5 秒后没有响应,取消请求
}, 5000);

fetch('https://api.example.com/slow-response', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Request aborted due to timeout');
    } else {
      console.error('Error:', error);
    }
  });

2. 并行请求

有时我们需要同时发起多个请求,并等待所有请求完成后再处理结果。这时可以使用 Promise.all() 来并行处理多个 fetch() 请求。

// 并行请求
const urls = [
  'https://api.example.com/data1',
  'https://api.example.com/data2',
  'https://api.example.com/data3'
];

Promise.all(urls.map(url => fetch(url).then(response => response.json())))
  .then(results => {
    console.log('All requests completed:', results);
  })
  .catch(error => console.error('Error:', error));

3. 流式处理

fetch() 还支持流式处理,允许我们在接收到部分数据时就开始处理,而不需要等待整个响应完成。这在处理大文件或实时数据时非常有用。

// 流式处理
fetch('https://api.example.com/stream')
  .then(response => {
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');

    return readStream(reader, decoder, '');
  });

function readStream(reader, decoder, result) {
  return reader.read().then(({ done, value }) => {
    if (done) {
      console.log('Stream complete:', result);
      return result;
    }

    result += decoder.decode(value, { stream: true });
    console.log('Received chunk:', result);

    return readStream(reader, decoder, result);
  });
}

Fetch API 与 XMLHttpRequest 的对比

为了更好地理解 Fetch API 的优势,我们可以通过一张表格来对比它与 XMLHttpRequest 的差异。

特性 Fetch API XMLHttpRequest
语法简洁性 简洁,基于 Promise 复杂,依赖回调函数
错误处理 自动捕获网络错误 需要手动检查 readyStatestatus
支持流式处理 支持 不支持
超时机制 需要借助 AbortController 不支持
并发请求 可以使用 Promise.all() 需要手动管理多个实例
浏览器兼容性 现代浏览器广泛支持 旧版浏览器支持

Fetch API 的局限性

虽然 Fetch API 有很多优点,但它也有一些局限性,尤其是在处理错误方面。fetch() 只会在网络请求失败时抛出错误(例如 DNS 解析失败、网络断开等),而不会在 HTTP 响应状态码为 4xx 或 5xx 时抛出错误。因此,你需要手动检查 response.ok 属性来判断请求是否成功。

fetch('https://api.example.com/404')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

结语

通过今天的讲座,相信大家对 Fetch API 有了更深入的了解。它不仅简化了 HTTP 请求的编写,还提供了更多的功能和灵活性。当然,Fetch API 也有它的局限性,但随着浏览器的不断更新,这些问题正在逐步得到解决。

如果你还没有开始使用 Fetch API,我强烈建议你尽快尝试一下。它会让你的代码更加简洁、易读,同时也更容易维护。

谢谢大家的聆听!如果有任何问题,欢迎随时提问。😊


参考资料:

  • [MDN Web Docs – Fetch API](引用自 MDN)
  • [WHATWG Fetch Standard](引用自 WHATWG)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注