Getting "TypeError: Failed to fetch" when the request hasn't actually failed

Getting "TypeError: Failed to fetch" when the request hasn't actually failed

我在我的 React 应用程序中使用 fetch API。该应用程序部署在服务器上并且运行良好。我测试了很多次。但是,应用程序突然停止工作,我不知道为什么。问题是当我发送 get 请求时,我收到了来自服务器的有效响应,但提取 API 正在捕获异常并显示 TypeError: Failed to fetch。我什至没有对代码进行任何更改,这是所有 React 组件的问题。

我收到了有效回复:

但同时出现此错误:

fetch(url)
.then(res => res.json())
.then(data => {
  // do something with data
})
.catch(rejected => {
    console.log(rejected);
});

当我删除凭据:“include”时,它可以在本地主机上运行,​​但不能在服务器上运行。

我尝试了 Whosebug 和 GitHub 上给出的所有解决方案,但对我来说就是行不通。

请注意,您的代码中存在一个不相关的问题,但稍后可能会影响您:您应该 return res.json() 否则您将不会捕获 JSON 解析或您自己的函数处理数据时发生的任何错误.

返回到您的错误:您无法 TypeError: failed to fetch 请求成功。您可能有另一个请求(检查您的 "network" 面板以查看所有请求)中断并导致记录此错误。此外,也许检查 "Preserve log" 以确保该面板未被任何不恰当的重定向清除。有时我碰巧有一个持久的 "console" 面板和一个已清除的 "network" 面板,这导致我在控制台中出现错误,这实际上与可见请求无关。你应该检查一下。

或者你(但那将是恶毒的)实际上在你的最终 .catch 中有一个硬编码的 console.log('TypeError: failed to fetch') ;)并且错误实际上在你的 .then() 中但是很难相信。

这可能与您从后端收到的响应有关。如果它在服务器上运行良好,那么问题可能出在响应 headers.

检查响应 headers 中 Access-Control-Allow-Origin 的值。通常当响应 headers' Access-Control-Allow-Origin 和请求的来源不匹配时,即使在收到响应后 fetch API 也会抛出 fail to fetch。

我知道它相对较旧 post 但是,我想分享对我有用的东西: 我只是在 url 中的“localhost”之前输入了“http://”。希望对大家有帮助。

如果您在本地主机服务器上调用提取,请使用 non-SSL,除非您拥有本地主机的有效证书。对于无效或自签名证书,提取将失败,尤其是在本地主机上。

我知道这个问题可能有一个 React-specific 原因,但它首先出现在“Typeerror: Failed to fetch”的搜索结果中,我想在这里列出所有可能的原因。

Fetch 规范列出了您从 Fetch API 中抛出 TypeError 的次数:https://fetch.spec.whatwg.org/#fetch-api

截至 2021 年 1 月的相关段落如下。这些是文本的节选。

4.6 HTTP-network 获取

To perform an HTTP-network fetch using request with an optional credentials flag, run these steps:
...
16. Run these steps in parallel:
...
2. If aborted, then:
...
3. Otherwise, if stream is readable, error stream with a TypeError.

To append a name/value name/value pair to a Headers object (headers), run these steps:

  1. Normalize value.
  2. If name is not a name or value is not a value, then throw a TypeError.
  3. If headers’s guard is "immutable", then throw a TypeError.

用给定的 object object:

填充 Headers object headers

To fill a Headers object headers with a given object object, run these steps:

  1. If object is a sequence, then for each header in object:
    1. If header does not contain exactly two items, then throw a TypeError.

方法步骤有时会抛出 TypeError:

The delete(name) method steps are:

  1. If name is not a name, then throw a TypeError.
  2. If this’s guard is "immutable", then throw a TypeError.

The get(name) method steps are:

  1. If name is not a name, then throw a TypeError.
  2. Return the result of getting name from this’s header list.

The has(name) method steps are:

  1. If name is not a name, then throw a TypeError.

The set(name, value) method steps are:

  1. Normalize value.
  2. If name is not a name or value is not a value, then throw a TypeError.
  3. If this’s guard is "immutable", then throw a TypeError.

To extract a body and a Content-Type value from object, with an optional boolean keepalive (default false), run these steps:
...
5. Switch on object:
...
ReadableStream
If keepalive is true, then throw a TypeError.
If object is disturbed or locked, then throw a TypeError.

在“Body mixin”部分中,如果您使用的是 FormData,则有几种方法可以引发 TypeError。我没有在这里列出它们,因为这会使这个答案很长。相关段落:https://fetch.spec.whatwg.org/#body-mixin

在“Request Class”部分中,新的 Request(input, init) 构造函数是潜在类型错误的雷区:

The new Request(input, init) constructor steps are:
...
6. If input is a string, then:
...
2. If parsedURL is a failure, then throw a TypeError.
3. IF parsedURL includes credentials, then throw a TypeError.
...
11. If init["window"] exists and is non-null, then throw a TypeError.
...
15. If init["referrer" exists, then:
...
1. Let referrer be init["referrer"].
2. If referrer is the empty string, then set request’s referrer to "no-referrer".
3. Otherwise:
1. Let parsedReferrer be the result of parsing referrer with baseURL.
2. If parsedReferrer is failure, then throw a TypeError.
...
18. If mode is "navigate", then throw a TypeError.
...
23. If request's cache mode is "only-if-cached" and request's mode is not "same-origin" then throw a TypeError.
...
27. If init["method"] exists, then:
...
2. If method is not a method or method is a forbidden method, then throw a TypeError.
...
32. If this’s request’s mode is "no-cors", then:
1. If this’s request’s method is not a CORS-safelisted method, then throw a TypeError.
...
35. If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.
...
38. If body is non-null and body's source is null, then:
1. If this’s request’s mode is neither "same-origin" nor "cors", then throw a TypeError.
...
39. If inputBody is body and input is disturbed or locked, then throw a TypeError.

The clone() method steps are:

  1. If this is disturbed or locked, then throw a TypeError.

在响应中 class:

The new Response(body, init) constructor steps are:
...
2. If init["statusText"] does not match the reason-phrase token production, then throw a TypeError.
...
8. If body is non-null, then:
1. If init["status"] is a null body status, then throw a TypeError.
...

The static redirect(url, status) method steps are:
...
2. If parsedURL is failure, then throw a TypeError.

The clone() method steps are:

  1. If this is disturbed or locked, then throw a TypeError.

在“Fetch 方法”部分

The fetch(input, init) method steps are:
...
9. Run the following in parallel:
To process response for response, run these substeps:
...
3. If response is a network error, then reject p with a TypeError and terminate these substeps.

除了这些潜在问题之外,还有一些 browser-specific 行为会引发 TypeError。例如,如果您将 keepalive 设置为 true 并且有效负载 > 64 KB,您将在 Chrome 上收到 TypeError,但相同的请求可以在 Firefox 中运行。这些行为未记录在规范中,但您可以通过谷歌搜索您在获取中设置的每个选项的限制来找到有关它们的信息。

就我而言,我在使用 jsfiddle 或 stackblitz 等在线 JS 工具时出现“TypeError”,问题是我的 url 是 http 而不是 https。

XHR 客户端在后台发送一个名为 pre-flight 的 HTTPOPTIONS 请求,以寻找特定的安全权限 headers,称为 CORS 允许 headers。如果未找到所需的 headers(因为您可能没有必要的权限),则结果为 TypeError,因为它实际上并未尝试发送您的 POST/GET 请求。您可以在浏览器控制台中观察到这种行为:看起来浏览器向同一位置发出了两个请求,首先是 HTTP 方法:OPTIONS。

我遇到这个问题是因为我没有在我的 flask 应用程序中添加 CORS。我需要添加它,然后它起作用了,这里是几行:

...
from flask_cors import CORS

def create_app(test_config=None ):

    app = Flask(__name__)

    app.config.from_object('config')  # Import things from config

    CORS(app)

    # CORS Headers 
    @app.after_request
    def after_request(response):
        response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true')
        response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
        return response

    ...

我在使用 Firebase Cloud Functions 时遇到了同样的错误,并且能够使用 CORS npm package 修复它,如下所示:

const functions = require("firebase-functions");
const cors = require('cors')({origin: true});

exports.exampleCORSFunction = functions.https.onRequest((req, res) => {
    cors(req, res, () => {
       //do your CORS stuff
       return res.send({response: "success"});
    });
});

将您的云函数包装在 CORS 模块中,它将 return header 值允许跨源。