即使我 return 一个 404,我的承诺的成功块总是执行

The success block of my promise always executes even when I return a 404

当用户使用不正确的电子邮件和密码登录时,我的客户端承诺的成功块仍然执行,即使服务器 returned a 400。

我将 Redux 与 React 结合使用,因此我正在调用一个动作创建器,它使用 axios 调用 HTTP 请求。我需要帮助来理解为什么我没有正确处理错误,因为我的应用程序的其余身份验证功能(如注册、注销等)都以相同的方式运行,即使我从服务器 returning 400 状态也是如此。

这是我从我的组件调用登录的地方,成功块总是执行:

handleFormSubmit({
  email, password
}) {
  this.props.loginUser({
    email, password
  }).then(() => {
    toastr.success("You are logged in!");
  }).catch(() => {
    toastr.warning("Could not log in");
  })
}

这是动作创建者 "loginUser",当我 return 来自服务器的 400 时,此函数的成功块不会 运行:

export function loginUser({ email, password }) {

  return function(dispatch) {

    return axios.post(`/users/login`, {
        email, password
      })
      .then(response => {

        dispatch({
          type: AUTH_USER
        });


        localStorage.setItem('token', response.headers['x-auth']);
        browserHistory.push('/feature');
      })
      .catch(() => {
        dispatch(authError('Incorrect email or password'));
      });
  }
}

这是路线'/users/login' 请注意,400 状态实际上 return:

app.post('/users/login', (req, res) => {
  var body = _.pick(req.body, ['email', 'password']);

  User.findByCredentials(body.email, body.password).then(user => {
    return user.generateAuthToken().then(token => {
      res.header('x-auth', token).send(user);
    });
  }).catch(e => {
    res.status(400).send();
  });
});

问题出在您的 loginUser 函数的 catch 处理程序中。 如果您想在 promise 链的更深处捕获错误,则需要在 catch 块中抛出错误。

  .catch(() => {
      dispatch(authError('Incorrect email or password'));
      throw Error('Incorrect email or password');
  });

你的问题是你误解了承诺中的 catch 条款。

如果只是带有拒绝处理程序的 then,您可以这样想:

.then(null, function(err) {
  // handle the error
})

意思是它只处理 promise 链中最后一个未处理的错误,无论发生什么,你都可以在它之后继续链接。

示例:

new Promise((resolve, reject) => {
  setTimeout(() => reject(Error('After 1 sec')), 1000)
})
.catch((err) => {
  console.log(`catch: ${err}`);
  return 5;
})
.then((five) => {
 // this chains because the error was handled before in the chain
 console.log(`catch.then: ${five}`); // 5
})
.catch(() => {
  console.log('No error happened between this error handler and previous so this is not logged');
});

要使错误从当前 catch 传播到下一个错误处理程序,您可以 return 一个被拒绝的 Promise(或重新抛出错误)以使链跳过所有成功处理程序直到下一个失败(或 catch)处理程序。

new Promise((resolve, reject) => {
  setTimeout(() => reject(Error('After 1 sec')), 1000)
})
.catch((err) => {
  // return a reject promise to propagate to the next error handler
  return Promise.reject(err);
  // can also `throw err;`
})
.then((nothing) => {
 // this doesn't happen now
 console.log(nothing);
})
.catch(console.error); // this logs the error

旁注:当您不在 Promise 链中提供拒绝处理程序(.then 中的第二个参数)时,默认拒绝处理程序的行为基本上如下:

function defaultRejectionHandler(err) {
  throw err;
}

这意味着它会重新抛出传递给它的任何错误,以便错误可以传播到您指定的下一个错误处理程序。