如何将错误对象传递给Socket.io回调函数

13

我正在使用socket.io的回调函数。

客户端代码:

socket.emit('someEvent', {data:1}, function(err, result) {
    console.log(err.message); 
});

服务器代码:

socket.on('someEvent', function(data, callback) {
    callback(new Error('testing error'));
});

通过上面的代码,客户端总是打印出undefined。如果我将服务器端代码更改为以下内容,就可以看到错误消息。

使用上述代码,客户端总是打印出undefined。如果我将服务器端代码更改为以下内容,则可以看到错误消息。

socket.on('someEvent', function(data, callback) {
    callback({message:'testing error'});
});

我可以成功地将自定义对象传递给客户端,但无法传递错误对象。有什么建议吗?

3个回答

13

socket.io的数据被序列化为JSON,它只能表示普通对象。您需要将任何错误序列化为可识别的普通对象格式,或者让 Socket.IO 的标准序列化处理(这将导致Error实例成为空普通对象)。


“or let the browser's standard serialization do its thing” 的确切含义是什么? - Golo Roden
2
@GoloRoden 抱歉,我只是想手动定义一个序列化格式或让socket.io序列化为JSON.stringify(new Error()) === '{}'这样是没有用的。 - loganfsmyth
3
这篇文章(http://www.devthought.com/2011/12/22/a-string-is-not-an-error/)中,Socket.io的创始人称应该总是传递错误对象而非简单的字符串等内容。在Socket.io文档中(http://socket.io/docs/server-api/#namespace#use(fn:function):namespace),他再次提到在回调中使用错误对象,但实际上将它们转换为空对象?我感到困惑! - Matt Fletcher
我也感到困惑。就像许多Node项目一样,我发现socket.io文档有点简略。我不得不阅读源代码并编写测试工具来理解它的某些方面。 - drekka

1
我认为奇怪的是,Socket.IO似乎没有提供明确的内置支持以有意义的方式传递Error对象。
如果你想在Socket.IO回调中正确序列化Error对象,你可以定义一个方法来指定如何处理Error消息的序列化,例如:.toJSON
if (!('toJSON' in Error.prototype)) {
    Object.defineProperty(Error.prototype, 'toJSON', {
    value: function () {
      let result = {}
      Object.getOwnPropertyNames(this).forEach((key) => {
        if (key === 'stack') return
        result[key] = this[key];
      }, this)
      return result
    },
    configurable: true,
    writable: true
  })
}

如果您正在从服务器发送消息,您需要在服务器上定义它;如果从客户端向服务器抛出错误,则还需要在客户端上定义它。

注意:在此示例中,返回错误时会剥离“stack”属性(以避免将内部信息暴露给客户端),但这可能是值得保留的内容,至少对于开发模式是如此。

更新:使用ES6更加容易

改编自我最近撰写的一篇博客文章:

https://medium.com/@iaincollins/error-handling-in-javascript-a6172ccdf9af

我很高兴地说,使用ES6可以更轻松/更清晰地完成此操作。
如果您像这样定义类来扩展Error:
class ValidationError extends Error {
  constructor(message) {
    super(message)
    this.name = 'ValidationError'
    this.message = message
  }

  toJSON() {
    return {
      error: {
        name: this.name,
        message: this.message,
        stacktrace: this.stack
      }
    }
  }
}

这个对象被传回来:

{ name: 'ValidationError' }

现在它看起来像这样:

{ 
  error: {
    name: 'ValidationError',
    message: 'A validation error',
    stacktrace: '…'
  }
}

你可以通过这样做来了解预期结果:

console.log(JSON.stringify(new ValidationError('A validation error'))

0
这是一个与普通错误对象一起使用的小型路由器函数。如果您不想让别人看到堆栈变量,可以将其删除。
socket.on('api', async (method, args, callback) {
  try {
    const result = await api[method](...args)
    callback(null, result)
  } catch (error) {
    const { name, message, stack } = error
    callback(error.toJSON ? error : { name, message, stack })
  }
})

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