本文详解如何在 JavaScript 中实现 Fetch API 的请求与响应拦截。由于原生 Fetch 不支持拦截器,文章介绍了通过猴子补丁重写 window.fetch 以及使用 fetch-intercept 库两种方案,涵盖 URL 修改、响应数据篡改、错误处理及 Node.js 环境下的兼容处理。
引言
本文内容译自 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 使用 GET 方法调用 API,具体形式如下:
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 请求和响应拦截详解的详细内容,更多关于 JavaScript Fetch API 请求响应拦截的资料请关注本站其它相关文章!