如何使用 fetch 从 400 错误请求中捕获响应 JSON?

How do I capture the response JSON from a 400 bad request with fetch?

我正在使用 React 17。我想提交一个获取请求并解析在出现 400 时返回的错误 JSON。我有这个代码

fetch(REACT_APP_PROXY + "/save_to_sheet_from_form/", {
  method: "post",
  headers: {
    "Content-Type": "application/json",
  },
  body: formData,
})
  .then((response) => {
    if (response.ok) {
      return response.json();
    } else {
      throw response;
    }
  })
  .then(function (data) {
    window.location.reload();
  })
  .catch((err) => {
    err.json().then((errorMessage) => {
      try {
        setErrors(JSON.parse(errorMessage));
      } catch (e) {
        return;
      }
    });
  });

在我的网络选项卡中,当出现 400 时我可以看到此响应

{"coop_name":["This field may not be blank."],"street":["This field may not be blank."],"city":["This field may not be blank."],"zip":["This field may not be blank."],"contact_name":["This field may not be blank."],"contact_email":["This field may not be blank."],"contact_phone":["This field may not be blank."]}

然而上面一行

err.json().then((errorMessage) => {

抛出语法错误。检索响应正文的正确方法是什么?

如果响应在不正常时仍可能是 JSON-parseable,则在其上使用 .json 将使浏览器尝试将结果解析为 JSON.

您需要考虑几个单独的类别:

  • 初始请求失败(这样第一个.then根本不会进入,而是进入.catch
  • 请求错误,服务器响应可解析 JSON
  • 服务器有问题并发回错误响应(例如 500 Internal Server Error)
  • 请求成功

您可以在解析响应的 header 时对此进行大部分逻辑测试。类似于

fetch(REACT_APP_PROXY + "/save_to_sheet_from_form/", {
    method: "post",
    headers: {
        "Content-Type": "application/json",
    },
    body: formData,
})
    .then((response) => {
        if (response.ok) {
            // will succeed unless server logic or your logic is off
            return response.json().then((data) => {
                window.location.reload();
            });
        } else if (response.status === 400) {
            // will succeed if the server will always respond with JSON with a 400 response
            return response.json().then((errorObj) => setErrors(errorObj));
        } else {
            // there was some other error in the response, such as status 500
            setErrors(response.statusText);
        }
    })
    .catch((err) => {
        // An unexpected error occurred which was not 400 nor while parsing the response header
        setErrors(String(err));
    });

如果在请求成功或失败时执行的逻辑并非完全微不足道,请继续使用独立的命名函数来提高可读性,而不是将所有内容都放在第一个 .then 中。 (例如if (response.ok) { return response.json().then(handleSuccess); }