哇哇哇图兔兔 發表於 2023-1-5 20:46:00

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

<p>本文翻译自 Intercepting JavaScript Fetch API requests and responses</p>
<p>拦截器是可用于预处理或后处理 HTTP 请求的代码块,有助于全局错误处理、身份验证、日志记录等。在本文中,你将学习如何拦截 JavaScript Fetch API 请求。</p>
<p>拦截 HTTP 请求一般有两种事件:请求和响应事件。请求拦截器应该在发送实际 HTTP 请求之前执行,而响应拦截器应该在到达发出请求的应用程序代码之前执行。</p>
<p>在深入研究代码之前,我们需要了解一些重要的事情。首先,Fetch API 本身不支持拦截器。其次,在 Node.js 中使用 Fetch API 需要额外的包。</p>
<h2 id="javascript-fetch-api">JavaScript Fetch API</h2>
<p>首先,让我们介绍一些 Fetch API 的基础,例如语法:</p>
<pre><code class="language-js">const fetchResponsePromise = fetch(resource [, init])
</code></pre>
<p><code>resource</code> 定义要获取的资源,该资源可以是 Request 对象,也可以是 URL。<code>init</code> 是一个可选对象,它将包含你想应用于此特定请求的任何自定义配置。</p>
<p>Fetch API 是基于 Promise 的。因此,当你调用 Fetch 方法时,你将得到一个 Promise 响应。在这里,它被称为 <code>fetchResponsePromise</code>,如上面的示例所示。</p>
<p>默认情况下,Fetch 使用 <code>GET</code> 方法调用 API,如下所示:</p>
<pre><code class="language-js">fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) =&gt; response.json())
.then((json) =&gt; console.log(json));
</code></pre>
<p>下面是一个使用 Fetch 发送 <code>POST</code> 请求的示例:</p>
<pre><code class="language-js">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) =&gt; response.json())
.then((json) =&gt; console.log(json));
</code></pre>
<p><code>POST</code> 请求必须有 <code>body</code>。 查看 Fetch 文档 了解更多详细信息。</p>
<h2 id="实现拦截">实现拦截</h2>
<p>有两种方法可以在 Fetch API 请求时添加拦截器:使用猴子补丁或者使用库 <code>fetch-intercept</code>。</p>
<h2 id="对-fetch-使用猴子补丁monkey-patching">对 Fetch 使用猴子补丁(monkey patching)</h2>
<p>为任何 JavaScript 函数或方法创建拦截器的一种方法是对其进行猴子修补。猴子补丁是一种用自己的函数版本覆盖原始函数的方法。</p>
<p>让我们一步一步地看看如何使用猴子补丁为 Fetch API 创建拦截器:</p>
<pre><code class="language-js">const { fetch: originalFetch } = window;

window.fetch = async (...args) =&gt; {
    let = args;
    // request interceptor here
    const response = await originalFetch(resource, config);
    // response interceptor here
    return response;
};
</code></pre>
<p>上面的代码使用自定义实现重写原始 Fetch 方法,并在其中调用原始 Fetch 方法。你可以使用这个样例代码来创建请求和响应拦截器。</p>
<h2 id="请求拦截器">请求拦截器</h2>
<p>在下面的示例中,我们将创建一个简单的请求拦截器,用于更改一个请求示例的 URL:</p>
<pre><code class="language-js">const { fetch: originalFetch } = window;
window.fetch = async (...args) =&gt; {
    let = 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) =&gt; response.json())
.then((json) =&gt; console.log(json));

// log
// {
//   "userId": 1,
//   "id": 2,
//   "title": "quis ut nam facilis et officia qui",
//   "completed": false
// }
</code></pre>
<p>这个 API 请求将从 <code>https://jsonplaceholder.typicode.com/todos/2</code> 获取数据,而不是 <code>https://jsonplaceholder.typicode.com/todos/1</code>,并展示 ID 为 <code>2</code> 的 <code>todo</code> 数据。</p>
<p><em>注意: 请求拦截器最常见的用例之一是更改身份验证的 headers。</em></p>
<h2 id="响应拦截器">响应拦截器</h2>
<p>响应拦截器将在 API 响应传递给实际调用者之前拦截它。让我们看看下面的代码:</p>
<pre><code class="language-js">const { fetch: originalFetch } = window;
window.fetch = async (...args) =&gt; {
let = args;

let response = await originalFetch(resource, config);

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

response.json = json;
return response;
};

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

// log
// {
//   "userId": 1,
//   "id": 1,
//   "title": "Intercepted: delectus aut autem",
//   "completed": false
// }
</code></pre>
<p>在上面的代码中,我们更改了 <code>json</code> 方法以返回一些自定义数据来替代原始数据。查看文档了解更多 可以更改的属性。</p>
<p>注意: <code>response</code> 只允许使用一次。因此,每次需要使用 <code>response</code> 时,都需要 克隆 response。</p>
<h2 id="错误处理">错误处理</h2>
<p>通过检查 <code>response.ok</code> 和 <code>response.status</code> 的值,可以很容易地处理请求的错误。在下面的代码片段中,可以拦截 404 错误</p>
<pre><code class="language-js">const { fetch: originalFetch } = window;
window.fetch = async (...args) =&gt; {
let = args;
let response = await originalFetch(resource, config);
if (!response.ok &amp;&amp; response.status === 404) {
    // 404 error handling
    return Promise.reject(response);
}
return response;
};
fetch('https://jsonplaceholder.typicode.com/todos/1000000')
.then((response) =&gt; response.json())
.then((json) =&gt; console.log(json))
.catch((error) =&gt; console.error(error));
</code></pre>
<h2 id="nodejs">Node.js</h2>
<p>你可以在 Node.js 中使用相同的方法。然而,Node.js 原生不支持 Fetch API (尽管对 Fetch API 的原生支持将在 Node.js 的未来版本中提供)。现在,你需要安装 Node Fetch 包,然后对 <code>fetch</code> 方法使用猴子补丁。【译:Node18已经支持了!】</p>
<h2 id="使用-fetch-intercept-库">使用 fetch-intercept 库</h2>
<p>如果你不喜欢做这些 <code>dirty</code> 的事情(双关语【译:我也不懂指什么?】) ,那么 fetch-intercept 库允许您使用更干净的 API 注册拦截器。您可以使用 npm 或 Yarn 来安装这个库,如下所示:</p>
<pre><code class="language-bash">npm install fetch-intercept whatwg-fetch --save
// or
yarn install fetch-intercept whatwg-fetch
</code></pre>
<p><em>注意: fetch-intercept 只支持浏览器,不能在 Node.js 中工作。因此,它还需要使用 whatwg-fetch 作为依赖项。</em></p>
<p>通过下面的代码,我们可以实现与我们的猴子补丁示例相同的请求和响应拦截器:</p>
<pre><code class="language-js">import * as fetchIntercept from 'fetch-intercept';

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

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

response: function (response) {
    const clonedResponse = response.clone();
    const json = () =&gt;
      clonedResponse
      .json()
      .then((data) =&gt; ({ ...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) =&gt; response.json())
.then((json) =&gt; console.log(json));

// unregister interceptors
unregister();
</code></pre>
<p><code>register</code> 方法允许你为 Fetch API 请求注册拦截器。它接受一个带有<code>request</code>,&nbsp;<code>requestError</code>,&nbsp;<code>response</code>, 和&nbsp;<code>responseError</code> 回调的对象。<code>register</code> 方法返回另一个可用于注销拦截器的方法。</p>
<p>Fetch API 本身不支持拦截器。但是,还有其他支持拦截器的 HTTP 请求库。看一下 Axios,它提供了开箱即用的功能。</p>
<h2 id="总结">总结</h2>
<p>在本文中,我们介绍了什么是 JavaScript 拦截器,学习了如何通过给 Fetch API 使用猴子补丁和使用 fetch-intercept 库来创建拦截器。</p>
<p>拦截器最初由 Angular 引入,对于各种各样的用例都很有帮助,比如帮助处理全局错误、身份验证、日志记录等等。你可以使用本文描述的方法将拦截器添加到 JavaScript 应用程序中,但是,请记住在 Node.js 需要添加额外的依赖。</p>
<p>我希望你喜欢这篇文章,如果有任何问题一定要留下评论。Happy coding!</p><br><br>
来源:https://www.cnblogs.com/wenruo/p/17028832.html
頁: [1]
查看完整版本: JavaScript 中如何拦截全局 Fetch API 的请求和响应?