【问题标题】:How to return error message objects to the client in Express?如何在 Express 中向客户端返回错误消息对象?
【发布时间】:2020-07-02 00:57:51
【问题描述】:

我有这段代码:

router.post('/users/login', async (req, res) => {
  try {
    const { email, password } = req.body
    const user = await User.findByCredentials(email, password)
    console.log(user) //false
    if (!user) {
      throw new Error('Login failed! Check authentication credentials')
    }
    const token = await user.generateAuthToken()
    res.status(200).json({ user, token })
  } catch (err) {
    console.log(err) //Error: Login failed! Check authentication credentials at C:\Users...
    res.status(400).json(err)
  }
})

在没有错误之前一切正常。当 Postman 中发生错误(user 是 false)时,我只返回了空对象 {}。还有res.status(400).json({error: err}),它给了我{ "err": {} }。

我想收到这样的对象{ "error": "Login failed! Check authentication credentials" }

【问题讨论】:

    标签: node.js express error-handling server


    【解决方案1】:

    JSON.stringifycan't capture non-enumerable object properties 正如 jfriend00 提到的那样,但有一些非常直接的解决方案似乎值得一提。

    一种方法是使用err.message 属性自己创建正确的对象,该属性包含提供给Error 构造函数的字符串:

    app.get("/foo", (req, res) => {
      try {
        throw new Error("hello world");
      }
      catch (err) {
        res.status(400).json({error: err.message});
      }
    });
    

    如果您真的无法触摸您的res.json 调用,另一种方法是使用throw 设置您喜欢的对象。我不喜欢这样,因为您丢失了堆栈跟踪信息(请参阅:1、2、3),但它存在:

    app.get("/foo", (req, res) => {
      try {
        throw {error: "hello world"};
      }
      catch (err) {
        res.status(400).json(err);
      }
    });
    

    在这两种情况下,客户都会看到

    {
        error: "hello world"
    }
    

    【讨论】:

      【解决方案2】:

      错误对象在 JSON 中不能很好地序列化,因为它们的某些属性是不可枚举的,因此当 res.json(err) 使用它时,JSON.stringify() 不包括它们。
      这就是为什么res.json(err) 没有显示你想要的。

      不包含不可枚举属性的可能原因是它们可能包含堆栈跟踪和其他不打算发送回客户端的信息。这只是 Error 对象如何工作以及 JSON.stringify() 是如何实现的副产品,res.json() 只是继承了这些问题以及两者之间的交互。我一直不明白为什么 .message 的主要属性是不可枚举的,因为这对我来说从来没有意义,但确实如此。

      有许多可能的解决方法:

      1. 您可以添加自己的 .json2() 方法,其中包含 Error 对象的所有属性(甚至是不可枚举的属性)。
      2. 您可以在调用next(err) 的地方使用Express error handling scheme,并提供一个被调用的集中式错误处理程序,您可以在那里对错误响应进行自己的序列化。
      3. 您可以创建一个 Error 的子类,用于填充将显示在 JSON 中的可枚举属性并使用它。

      选项 #3 可能如下所示:

      class RouteError extends Error {
          constructor(msg, statusCode = 500) {
              super(msg);
              // define my own enumerable properties so they
              // will show up in JSON automatically
              this.error = msg;
              this.statusCode = statusCode;
          }
      }
      
      router.post('/users/login', async (req, res) => {
        try {
          const { email, password } = req.body
          const user = await User.findByCredentials(email, password)
          console.log(user) //false
          if (!user) {
            throw new RouteError('Login failed! Check authentication credentials', 401)
          }
          const token = await user.generateAuthToken()
          res.status(200).json({ user, token })
        } catch (err) {
          console.log(err) //Error: Login failed! Check authentication credentials at C:\Users...
          res.status(err.statusCode).json(err);
        }
      });
      

      这个例子会产生这个响应:

      {"error":"Login failed! Check authentication credentials","statusCode":401}
      

      【讨论】:

      • 感谢您的回答,这真的很有帮助,res.status(400).json({ error: err.message }) 也可以按我的意愿工作。
      • @kapsztat12 - 是的,你的建议很简单。我仍然不知道为什么 .message 属性设置为不可枚举。我明白为什么.stack 是。
      【解决方案3】:

      如果用户为 null 或为空,您可以抛出错误。另一个帖子回答了类似的问题。

      Node.js with Express - throw Error vs next(error)

      【讨论】:

      • 他们已经抛出错误。这就是没有按照他们想要的方式工作。
      猜你喜欢
      • 2012-12-12
      • 2014-09-21
      • 2019-01-26
      • 1970-01-01
      • 2021-01-26
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多