在fetch期间的try-catch无法捕获403错误

8
我正在使用ReactJS进行PUT请求,但是当我输入错误的电子邮件/密码组合时,即使我试图捕获所有错误并在errorDiv中显示它们,Chrome也会记录下这些错误。

enter image description here

async connect(event) {
  try {
    const userObject = {
      username: this.state.userName,
      password: this.state.password
    };
    if (!userObject.username || !userObject.password) {
      throw Error('The username/password is empty.');
    }
    let response = await fetch(('someurl.com'), {
      method: "PUT",
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(userObject)
    });
    let resJSON = await response.json();
    if (!response.ok) {
      throw Error(resJSON.message);
    }
    console.info(resJSON.message);
    console.info(resJSON.message.auth_token);
    window.location = "/ledger/home";
  } catch (e) {
    document.getElementById("errorDiv").style.display = 'block';
    document.getElementById("errorDiv").innerHTML = e;
  }
}


代码没问题。无法复制问题,https://stackblitz.com/edit/react-pb51rz - Estus Flask
3个回答

10
根据mdn文档,fetch仅在遇到网络错误时才会抛出异常。
404(或者403)不属于网络错误。

fetch()返回的Promise对象即使响应状态码为HTTP 404或500也不会拒绝,而是正常解析(ok属性设为false),只有在网络故障或请求未完成时才会拒绝。

例如,404并不构成网络错误。要准确检测fetch()是否成功,需要先检查Promise对象是否已经解析,然后再检查Response.ok属性是否为true。


所以我没有办法捕获并将其显示给用户,而不是自动创建日志吗? - Muhammad Ali

7

我完全同意@Sagiv的看法,但是有一个快速解决方法,尽管这不是建议使用的方式。在try或promise.then()内部,您需要进行以下检查。

const res = await fetch();
console.log(res);    // You can see the response status here by doing res.status

因此,通过一些简单的检查,可以解决或拒绝一个承诺。例如,在您的情况下。
async connect(event) {
  try {
    const userObject = {
      username: this.state.userName,
      password: this.state.password
    };
    if (!userObject.username || !userObject.password) {
      throw Error('The username/password is empty.');
    }
    let response = await fetch('someurl.com', {
      method: 'PUT',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(userObject)
    });
    if (response.status === 403) throw new Error('403 is unacceptable for me!');
    let resJSON = await response.json();
    if (!response.ok) {
      throw Error(resJSON.message);
    }
    console.info(resJSON.message);
    console.info(resJSON.message.auth_token);
    window.location = '/ledger/home';
  } catch (e) {
    document.getElementById('errorDiv').style.display = 'block';
    document.getElementById('errorDiv').innerHTML = e;
  }
}

我强烈推荐使用axios。关于fetch问题,您可以参考这个链接


1
这是因为你抛出了错误,然后捕获了部分代码不执行。请尝试以下代码:

async connect(event) {
  try {
    const userObject = {
      username: this.state.userName,
      password: this.state.password
    };
    if (!userObject.username || !userObject.password) {
      throw Error('The username/password is empty.');
    }
    let response = await fetch(('someurl.com'), {
      method: "PUT",
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(userObject)
    }).then(response => {
       response.json();
       console.info(resJSON.message);
       console.info(resJSON.message.auth_token);
       window.location = "/ledger/home";
    }).catch(e => {
    document.getElementById("errorDiv").style.display = 'block';
    document.getElementById("errorDiv").innerHTML = e;
  })
}

最后一行之后我需要再加一个catch吗?因为.catch是在try内部的。 - Muhammad Ali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接