tornado.websocket — 浏览器双向通信

WebSocket 协议的实现。

WebSockets 允许浏览器和服务器之间的双向通信。所有主要浏览器的当前版本都支持 WebSockets。

此模块实现了 WebSocket 协议的最终版本,如 RFC 6455 中定义。

版本 4.0 中的更改: 删除了对草案 76 协议版本的支持。

class tornado.websocket.WebSocketHandler(application: Application, request: HTTPServerRequest, **kwargs: Any)[source]

子类化此类以创建一个基本的 WebSocket 处理程序。

覆盖 on_message 来处理传入的消息,并使用 write_message 向客户端发送消息。您还可以覆盖 openon_close 来处理打开和关闭的连接。

可以通过覆盖 set_default_headersprepare 发送自定义升级响应头。

有关 JavaScript 接口的详细信息,请参阅 http://dev.w3.org/html5/websockets/。该协议在 http://tools.ietf.org/html/rfc6455 中指定。

以下是一个 WebSocket 处理程序示例,它将所有接收到的消息回显给客户端

class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        self.write_message(u"You said: " + message)

    def on_close(self):
        print("WebSocket closed")

WebSockets 不是标准的 HTTP 连接。 “握手”是 HTTP,但在握手之后,协议是基于消息的。因此,大多数 Tornado HTTP 功能在这种类型的处理程序中不可用。您可用的唯一通信方法是 write_message()ping()close()。同样,您的请求处理程序类应该实现 open() 方法,而不是 get()post()

如果将上面的处理程序映射到应用程序中的 /websocket,则可以使用 JavaScript 在其中调用它

var ws = new WebSocket("ws://127.0.0.1:8888/websocket");
ws.onopen = function() {
   ws.send("Hello, world");
};
ws.onmessage = function (evt) {
   alert(evt.data);
};

此脚本弹出一个警报框,上面写着“你说:您好,世界”。

Web 浏览器允许任何网站打开到任何其他网站的 websocket 连接,而不是使用管理 JavaScript 来自其他网络访问的同源策略。这可能会令人惊讶,并且是一个潜在的安全漏洞,因此自从 Tornado 4.0 以来,WebSocketHandler 要求希望接收跨域 websockets 的应用程序通过覆盖 check_origin 方法选择加入(有关详细信息,请参阅该方法的文档)。未能做到这一点是建立 websocket 连接时出现 403 错误的最可能原因。

当使用安全 websocket 连接 (wss://) 和自签名证书时,来自浏览器的连接可能会失败,因为它想要显示“接受此证书”对话框,但没有地方显示它。您必须首先使用相同的证书访问一个普通的 HTML 页面以接受它,然后 websocket 连接才会成功。

如果应用程序设置 websocket_ping_interval 具有非零值,则会定期发送 ping,并且如果在 websocket_ping_timeout 之前没有收到响应,则连接将关闭。

大于 websocket_max_message_size 应用程序设置(默认 10MiB)的消息将不被接受。

版本 4.5 中的更改: 添加了 websocket_ping_intervalwebsocket_ping_timeoutwebsocket_max_message_size

事件处理程序

WebSocketHandler.open(*args: str, **kwargs: str) Optional[Awaitable[None]][source]

当打开新的 WebSocket 时调用。

传递给 open 的参数是从 tornado.web.URLSpec 正则表达式中提取的,就像传递给 tornado.web.RequestHandler.get 的参数一样。

open 可以是一个协程。在 open 返回之前,不会调用 on_message

版本 5.1 中的更改: open 可以是一个协程。

WebSocketHandler.on_message(message: Union[str, bytes]) Optional[Awaitable[None]][source]

处理 WebSocket 上的传入消息

必须覆盖此方法。

版本 4.5 中的更改: on_message 可以是一个协程。

WebSocketHandler.on_close() None[source]

当 WebSocket 关闭时调用。

如果连接干净地关闭,并且提供了状态码或原因短语,则这些值将作为属性 self.close_codeself.close_reason 可用。

版本 4.0 中的变更: 添加了 close_codeclose_reason 属性。

WebSocketHandler.select_subprotocol(subprotocols: List[str]) Optional[str][source]

覆盖以实现子协议协商。

subprotocols 是一个字符串列表,标识客户端提出的子协议。此方法可以被覆盖以返回这些字符串之一以选择它,或者返回 None 以不选择子协议。

无法选择子协议不会自动中止连接,尽管如果未选择任何提出的子协议,客户端可能会关闭连接。

该列表可能为空,在这种情况下,此方法必须返回 None。即使没有提出子协议,此方法也始终被精确地调用一次,以便处理程序可以被告知此事实。

版本 5.1 中的变更: 以前,如果客户端未提出任何子协议,则此方法将使用包含空字符串的列表而不是空列表调用。

WebSocketHandler.selected_subprotocol

select_subprotocol 返回的子协议。

版本 5.1 中的新增内容。

WebSocketHandler.on_ping(data: bytes) None[source]

当收到 ping 帧时调用。

输出

WebSocketHandler.write_message(message: Union[bytes, str, Dict[str, Any]], binary: bool = False) Future[None][source]

将给定消息发送到此 Web Socket 的客户端。

消息可以是字符串或字典(将被编码为 json)。如果 binary 参数为假,则消息将以 utf8 形式发送;在二进制模式下,允许使用任何字节字符串。

如果连接已关闭,则引发 WebSocketClosedError。返回一个 Future,可用于流量控制。

版本 3.2 中的变更: WebSocketClosedError 已被添加(以前关闭的连接会引发 AttributeError)。

版本 4.3 中的变更: 返回一个 Future,可用于流量控制。

版本 5.0 中的变更: 一致地引发 WebSocketClosedError。以前有时会引发 StreamClosedError

WebSocketHandler.close(code: Optional[int] = None, reason: Optional[str] = None) None[source]

关闭此 Web Socket。

一旦关闭握手成功,套接字将被关闭。

code 可以是数字状态码,取自 RFC 6455 第 7.4.1 节 中定义的值。reason 可以是关于连接为何关闭的文本消息。这些值可用于客户端,但不会以其他方式由 websocket 协议解释。

版本 4.0 中的变更: 添加了 codereason 参数。

配置

WebSocketHandler.check_origin(origin: str) bool[source]

覆盖以支持允许替代来源。

origin 参数是 Origin HTTP 标头的值,即负责启动此请求的 url。此方法不会对未发送此标头的客户端调用;此类请求始终允许(因为所有实现 WebSockets 的浏览器都支持此标头,而非浏览器客户端没有相同的跨站点安全问题)。

应返回 True 以接受请求,或返回 False 以拒绝请求。默认情况下,拒绝所有来自与当前主机不同的主机的来源的请求。

这是针对浏览器上跨站脚本攻击的安全保护,因为 WebSockets 可以绕过通常的同源策略,并且不使用 CORS 头部。

警告

这是一个重要的安全措施;请不要在不了解安全影响的情况下禁用它。特别是,如果您的身份验证是基于 cookie 的,您必须要么限制 check_origin() 允许的来源,要么为 websocket 连接实现您自己的类似 XSRF 的保护。有关更多信息,请参阅 这些 文章

要接受所有跨源流量(在 Tornado 4.0 之前是默认设置),只需重写此方法以始终返回 True

def check_origin(self, origin):
    return True

要允许来自您网站任何子域的连接,您可以执行以下操作

def check_origin(self, origin):
    parsed_origin = urllib.parse.urlparse(origin)
    return parsed_origin.netloc.endswith(".mydomain.com")

版本 4.0 中新增。

WebSocketHandler.get_compression_options() Optional[Dict[str, Any]][source]

覆盖以返回连接的压缩选项。

如果此方法返回 None(默认值),则压缩将被禁用。如果它返回一个字典(即使是空字典),它将被启用。字典的内容可用于控制以下压缩选项

compression_level 指定压缩级别。

mem_level 指定用于内部压缩状态的内存量。

这些参数在以下位置有详细说明: https://docs.pythonlang.cn/3.6/library/zlib.html#zlib.compressobj

版本 4.1 中新增。

版本 4.5 中变更: 添加了 compression_levelmem_level

WebSocketHandler.set_nodelay(value: bool) None[source]

为该流设置无延迟标志。

默认情况下,小消息可能会被延迟和/或合并,以最大程度地减少发送的数据包数量。这有时会导致 200-500 毫秒的延迟,因为 Nagle 算法与 TCP 延迟 ACK 之间的交互。要减少这种延迟(以可能增加带宽使用率为代价),在 websocket 连接建立后,调用 self.set_nodelay(True)

有关更多详细信息,请参阅 BaseIOStream.set_nodelay

版本 3.1 中新增。

其他

WebSocketHandler.ping(data: Union[str, bytes] = b'') None[source]

向远程端发送 ping 帧。

data 参数允许将少量数据(最多 125 字节)作为 ping 消息的一部分发送。请注意,并非所有 websocket 实现都将此数据公开给应用程序。

考虑使用 websocket_ping_interval 应用程序设置,而不是手动发送 ping。

版本 5.1 中变更: data 参数现在是可选的。

WebSocketHandler.on_pong(data: bytes) None[source]

在收到对 ping 帧的响应时调用。

exception tornado.websocket.WebSocketClosedError[source]

由对已关闭连接的操作引发。

版本 3.2 中新增。

客户端支持

tornado.websocket.websocket_connect(url: Union[str, HTTPRequest], callback: Optional[Callable[[Future[WebSocketClientConnection]], None]] = None, connect_timeout: Optional[float] = None, on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, compression_options: Optional[Dict[str, Any]] = None, ping_interval: Optional[float] = None, ping_timeout: Optional[float] = None, max_message_size: int = 10485760, subprotocols: Optional[List[str]] = None, resolver: Optional[Resolver] = None) Awaitable[WebSocketClientConnection][source]

客户端 WebSocket 支持。

接收一个 URL 并返回一个 Future,其结果是 WebSocketClientConnection

compression_options 的解释方式与 WebSocketHandler.get_compression_options 的返回值相同。

连接支持两种操作风格。在协程风格中,应用程序通常在循环中调用 read_message

conn = yield websocket_connect(url)
while True:
    msg = yield conn.read_message()
    if msg is None: break
    # Do something with msg

在回调风格中,将 on_message_callback 传递给 websocket_connect。 在两种风格中,None 消息表示连接已关闭。

subprotocols 可以是指定建议子协议的字符串列表。 当连接完成时,可以在连接对象的 selected_subprotocol 属性中找到选定的协议。

版本 3.2 中变更: 也接受 HTTPRequest 对象代替 URL。

版本 4.1 中变更: 添加了 compression_optionson_message_callback

版本 4.5 中变更: 添加了 ping_intervalping_timeoutmax_message_size 参数,它们在 WebSocketHandler 中具有相同的含义。

版本 5.0 中变更: 已删除 io_loop 参数(自版本 4.1 起已弃用)。

版本 5.1 中变更: 添加了 subprotocols 参数。

版本 6.3 中变更: 添加了 resolver 参数。

class tornado.websocket.WebSocketClientConnection(request: HTTPRequest, on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, compression_options: Optional[Dict[str, Any]] = None, ping_interval: Optional[float] = None, ping_timeout: Optional[float] = None, max_message_size: int = 10485760, subprotocols: Optional[List[str]] = None, resolver: Optional[Resolver] = None)[source]

WebSocket 客户端连接。

此类不应直接实例化;使用 websocket_connect 函数代替。

close(code: Optional[int] = None, reason: Optional[str] = None) None[source]

关闭 websocket 连接。

codereasonWebSocketHandler.close 中有说明。

版本 3.2 中新增。

版本 4.0 中的变更: 添加了 codereason 参数。

write_message(message: Union[str, bytes, Dict[str, Any]], binary: bool = False) Future[None][source]

向 WebSocket 服务器发送消息。

如果流已关闭,则会引发 WebSocketClosedError。返回一个 Future,可用于流量控制。

Changed in version 5.0: StreamClosedError 更改为 WebSocketClosedError,在关闭流时引发的异常。

read_message(callback: Optional[Callable[[Future[Union[None, str, bytes]]], None]] = None) Awaitable[Union[None, str, bytes]][source]

从 WebSocket 服务器读取消息。

如果在 WebSocket 初始化时指定了 on_message_callback,则此函数将永远不会返回消息。

返回一个 future,其结果是消息,如果连接关闭则为 None。如果给出了回调参数,它将在 future 就绪时调用。

ping(data: bytes = b'') None[source]

向远程端发送 ping 帧。

data 参数允许将少量数据(最多 125 字节)作为 ping 消息的一部分发送。请注意,并非所有 websocket 实现都将此数据公开给应用程序。

请考虑使用 ping_interval 参数到 websocket_connect 而不是手动发送 ping。

版本 5.1 中的新增内容。

property selected_subprotocol: Optional[str]

服务器选择的子协议。

版本 5.1 中的新增内容。