Tornado WebSocket on_message 方法中的异常被忽略

Exception ignored in Tornado WebSocket on_message method

我有以下 class:

class SessionHandler(tornado.websocket.WebSocketHandler):

@tornado.gen.coroutine       
def on_message(self):
          yield self.application.c.check("xxx@gmail.com")

check() 函数类似于

   @tornado.gen.coroutine
   def check(self,id):

      if id not in self.AUTH_METHOD.keys():
         raise InvalidXX

InvalidXX 是继承自 Exception class.

的用户定义异常

引发此异常时,Tornado 控制台不会显示任何内容。但是,当我在它们周围添加 try/except 子句时,会发现异常。我不明白为什么没有将此异常传播到控制台。其他例外MongoDB 中的重复键被传播并显示到控制台。

[此答案适用于 Tornado 4.4 及更早版本。从 Tornado 4.5 开始,on_message 可能是协程,原始问题中的代码将起作用]

协程的调用方式与常规函数不同(即它们必须使用 yield 调用)。因此,当您定义要由框架调用的方法时,您应该只在文档说 "this method may be a coroutine" 时才使用协程。 WebSocketHandler.on_message 可能不是协程(从 Tornado 4.3 开始)。

相反,您可以使用 IOLoop.spawn_callbackon_message 回调中启动一个独立的协程。

def on_message(self, msg):
    IOLoop.current().spawn_callback(process_message, msg)

@gen.coroutine
def process_message(self, msg):
    ...

这里的一个重要区别是 spawn_callback 将协程与 WebSocketHandler 中接收消息的代码分离:您可能会在第一个回调产生之前得到第二个 on_message 调用一个已经完成了。使用 tornado.lockstornado.queues 模块中的方法来管理这种并发性。 (相比之下,在 RequestHandler.data_received 中, 可能 是协程,在处理第二个数据块之前,您不会获得第二个数据块,并且未捕获的异常将中止连接)