You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tornado WebSocket在Firefox关标签时无法捕获StreamClosedError异常求助

解决Tornado WebSocket在Firefox关闭标签页时的未捕获异常

嘿,我一眼就发现问题出在你异步操作的异常处理上——你在on_message里调用write_message但没有await它返回的Future,这就导致这个Future抛出的异常没进入你的try/except块,反而逃逸到了asyncio的全局异常处理器,所以才会出现那些你抓不到的ERROR日志。

问题根源

Tornado的write_message在异步模式下会返回一个Future对象,当WebSocket连接已经被关闭(比如Firefox关标签页时快速切断连接),这个Future就会抛出StreamClosedError或者WebSocketClosedError。但你没去await这个Future,所以这些异常根本没机会被你的try块捕获,只能在后台被asyncio检测到,打印出未处理的异常信息。

修复方案

最简单的修复就是给write_message加上await,这样异常就能被你的try/except正常捕获了:

async def on_message(self, message):
    print(message)
    while True:
        try:
            # 等待write_message完成,确保异常能进入try块被捕获
            await self.write_message(self.users[self].request_data())
        except tornado.iostream.StreamClosedError as e:
            print('StreamClosedError:', e)
            break
        except tornado.websocket.WebSocketClosedError as e:
            print('WebSocketClosedError:', e)
            break
        except KeyError as e:
            print('KeyError:', e)
            break
        await gen.sleep(1)

额外兜底方案

如果还是偶尔有漏网的异常,你可以给你的WebSocketHandler类加一个on_exception方法,统一处理所有未被捕获的异常:

def on_exception(self, exception):
    # 专门处理WebSocket连接关闭相关的异常,避免日志报错
    if isinstance(exception, (tornado.iostream.StreamClosedError, tornado.websocket.WebSocketClosedError)):
        print('WebSocket连接已关闭,忽略异常:', exception)
        return
    # 其他异常交给父类的默认处理逻辑
    super().on_exception(exception)

这个方法会在WebSocketHandler的任何方法抛出未捕获异常时自动触发,能帮你把这类连接关闭的异常全部兜底处理掉,不会再出现那些烦人的ERROR日志。

为啥只有Firefox会出这问题?

其实本质问题和浏览器无关,但Firefox在关闭标签页时,可能会更激进地切断WebSocket连接,导致write_message的Future立刻触发异常,而因为你没await它,就暴露了这个问题。Chrome等浏览器的连接关闭流程可能更平缓,所以不容易复现,但问题本身还是异步操作的异常没被正确捕获。

内容的提问来源于stack exchange,提问作者Dušan Jovanović

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:56:48