JavaScript 中如何拦截全局 Fetch API 的请求和响应

作者:异步漫步时间:2026-10-26 08:51:46浏览:627

本文详解如何在 JavaScript 中拦截全局 Fetch API 的请求和响应。通过介绍猴子补丁(Monkey Patching)和 fetch-intercept 库两种方案,演示如何修改 URL、处理身份验证、自定义响应数据及错误处理。同时涵盖 Node.js 环境下的兼容性及 Axios 等替代库的对比,帮助开发者实现全局 HTTP 请求管理。

本文译自 Intercepting JavaScript Fetch API requests and responses

拦截器是用于预处理或后处理 HTTP 请求的代码片段,可辅助全局错误处理、身份验证及日志记录。本文旨在讲解如何拦截 JavaScript Fetch API 请求。

HTTP 请求拦截主要涉及请求与响应两类事件。请求拦截器需在发送实际 HTTP 请求前执行,响应拦截器则在数据返回至调用应用代码前执行。

在编写代码前需明确两点:首先,Fetch API 原生不支持拦截器;其次,在 Node.js 环境中使用 Fetch API 需依赖额外包。

JavaScript Fetch API

首先介绍 Fetch API 基础语法:

const fetchResponsePromise = fetch(resource [, init])

resource 指定待获取资源,可为 Request 对象或 URL。init 为可选配置对象,用于定义此特定请求的自定义设置。

Fetch API 基于 Promise 机制。调用 Fetch 方法将返回一个 Promise 响应,此处称为 fetchResponsePromise,如前述示例所示。

默认情况下,Fetch 调用 API 使用 GET 方法,示例如下:

fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => response.json())
.then((json) => console.log(json));

以下示例演示如何使用 Fetch 发送 POST 请求:

fetch('https://jsonplaceholder.typicode.com/todos', {
  method: 'POST',
  body: JSON.stringify({
    completed: false,
    id: 1,
    title: 'New Todo',
    userId: 1,
  }),
  headers: new Headers({
    'Content-Type': 'application/json; charset=UTF-8',
  }),
})
.then((response) => response.json())
.then((json) => console.log(json));

POST 请求必须包含 body。请参阅 Fetch 文档以获取更多信息。

实现拦截

在 Fetch API 请求中添加拦截器有两种方式:采用猴子补丁(Monkey Patching)或借助 fetch-intercept 库。

对 Fetch 应用猴子补丁

为 JavaScript 函数或方法创建拦截器的一种手段是进行猴子修补。该方法通过用自定义函数版本覆盖原始函数来实现。

以下步骤展示如何利用猴子补丁为 Fetch API 创建拦截器:

const { fetch: originalFetch } = window;

window.fetch = async (...args) => {
    let [resource, config ] = args;
    // request interceptor here
    const response = await originalFetch(resource, config);
    // response interceptor here
    return response;
};

上述代码通过自定义实现重写原始 Fetch 方法,并在其中调用原始 Fetch。可基于此样例代码构建请求与响应拦截器。

请求拦截器

在以下示例中,我们将构建一个简单的请求拦截器,用于修改特定请求的 URL:

const { fetch: originalFetch } = window;
window.fetch = async (...args) => {
    let [resource, config ] = args;

    // request interceptor starts
    resource = 'https://jsonplaceholder.typicode.com/todos/2';
    // request interceptor ends

    const response = await originalFetch(resource, config);

    // response interceptor here
    return response;
};


fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => response.json())
.then((json) => console.log(json));

// log
// {
//   "userId": 1,
//   "id": 2,
//   "title": "quis ut nam facilis et officia qui",
//   "completed": false
// }

该 API 请求将从 https://jsonplaceholder.typicode.com/todos/2 获取数据,而非 https://jsonplaceholder.typicode.com/todos/1,并展示 ID 为 2 的 todo 数据。

注意:请求拦截器最常见的应用场景之一是修改身份验证相关的 headers。

响应拦截器

响应拦截器会在 API 响应传递给实际调用者之前对其进行拦截。代码如下:

const { fetch: originalFetch } = window;
window.fetch = async (...args) => {
  let [resource, config] = args;

  let response = await originalFetch(resource, config);

  // response interceptor
  const json = () =>
    response
      .clone()
      .json()
      .then((data) => ({ ...data, title: `Intercepted: ${data.title}` }));

  response.json = json;
  return response;
};

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then((response) => response.json())
  .then((json) => console.log(json));

// log
// {
//     "userId": 1,
//     "id": 1,
//     "title": "Intercepted: delectus aut autem",
//     "completed": false
// }

在上述代码中,我们重写了 json 方法以返回自定义数据替代原始数据。查阅文档可了解其他可修改的属性。

注意:response 仅允许读取一次。因此,每次需使用 response 时,必须克隆 response。

错误处理

通过检查 response.ok 和 response.status 的值,可轻松处理请求错误。以下代码片段展示了如何拦截 404 错误:

const { fetch: originalFetch } = window;
window.fetch = async (...args) => {
  let [resource, config] = args;
  let response = await originalFetch(resource, config);
  if (!response.ok && response.status === 404) {
    // 404 error handling
    return Promise.reject(response);
  }
  return response;
};
fetch('https://jsonplaceholder.typicode.com/todos/1000000')
  .then((response) => response.json())
  .then((json) => console.log(json))
  .catch((error) => console.error(error));

Node.js

可在 Node.js 中使用相同方法。然而,Node.js 原生暂不支持 Fetch API(尽管未来版本计划提供原生支持)。目前需安装 Node Fetch 包,并对 fetch 方法应用猴子补丁。【译:Node18已支持!】

使用 fetch-intercept 库

若不愿处理这些 dirty 操作(双关语【译:我也不懂指什么?】),fetch-intercept 库提供了更简洁的 API 以注册拦截器。可通过 npm 或 Yarn 安装该库,如下所示:

npm install fetch-intercept whatwg-fetch --save
// or
yarn install fetch-intercept whatwg-fetch

注意:fetch-intercept 仅支持浏览器环境,无法在 Node.js 中运行。因此,还需依赖 whatwg-fetch。

通过以下代码,可实现与猴子补丁示例等效的请求和响应拦截器:

import * as fetchIntercept from 'fetch-intercept';

const unregister = fetchIntercept.register({
  request: function (url, config) {
    const modifiedUrl = `https://jsonplaceholder.typicode.com/todos/2`;
    return [modifiedUrl, config];
  },

  requestError: function (error) {
    return Promise.reject(error);
  },

  response: function (response) {
    const clonedResponse = response.clone();
    const json = () =>
      clonedResponse
        .json()
        .then((data) => ({ ...data, title: `Intercepted: ${data.title}` }));

    response.json = json;
    return response;
  },

  responseError: function (error) {
    return Promise.reject(error);
  },
});

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then((response) => response.json())
  .then((json) => console.log(json));

// unregister interceptors
unregister();

register 方法允许为 Fetch API 请求注册拦截器。它接收包含 request, requestError, response, 和 responseError 回调的对象。register 方法返回一个可用于注销拦截器的函数。

Fetch API 本身不支持拦截器,但存在其他支持拦截器的 HTTP 请求库。例如 Axios,它提供了开箱即用的拦截器功能。

总结

本文介绍了 JavaScript 拦截器的概念,并学习了如何通过给 Fetch API 应用猴子补丁及使用 fetch-intercept 库来创建拦截器。

拦截器最初由 Angular 引入,适用于多种用例,如处理全局错误、身份验证及日志记录等。可使用本文描述的方法将拦截器集成至 JavaScript 应用,但需注意在 Node.js 中需添加额外依赖。

关于 JavaScript 中如何拦截全局 Fetch API 的请求和响应问题的文章至此结束,更多相关 js 拦截全局 Fetch API 内容请搜索本站历史文章或继续浏览以下相关文章,希望大家以后多多支持本站!

作者最新文章