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
向客户端发送消息。您还可以覆盖open
和on_close
来处理打开和关闭的连接。可以通过覆盖
set_default_headers
或prepare
发送自定义升级响应头。有关 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_interval
、websocket_ping_timeout
和websocket_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_code
和self.close_reason
可用。版本 4.0 中的变更: 添加了
close_code
和close_reason
属性。
- WebSocketHandler.select_subprotocol(subprotocols: List[str]) Optional[str] [source]¶
覆盖以实现子协议协商。
subprotocols
是一个字符串列表,标识客户端提出的子协议。此方法可以被覆盖以返回这些字符串之一以选择它,或者返回None
以不选择子协议。无法选择子协议不会自动中止连接,尽管如果未选择任何提出的子协议,客户端可能会关闭连接。
该列表可能为空,在这种情况下,此方法必须返回 None。即使没有提出子协议,此方法也始终被精确地调用一次,以便处理程序可以被告知此事实。
版本 5.1 中的变更: 以前,如果客户端未提出任何子协议,则此方法将使用包含空字符串的列表而不是空列表调用。
- WebSocketHandler.selected_subprotocol¶
由
select_subprotocol
返回的子协议。版本 5.1 中的新增内容。
输出¶
- 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.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
指定用于内部压缩状态的内存量。版本 4.1 中新增。
版本 4.5 中变更: 添加了
compression_level
和mem_level
。
- WebSocketHandler.set_nodelay(value: bool) None [source]¶
为该流设置无延迟标志。
默认情况下,小消息可能会被延迟和/或合并,以最大程度地减少发送的数据包数量。这有时会导致 200-500 毫秒的延迟,因为 Nagle 算法与 TCP 延迟 ACK 之间的交互。要减少这种延迟(以可能增加带宽使用率为代价),在 websocket 连接建立后,调用
self.set_nodelay(True)
。有关更多详细信息,请参阅
BaseIOStream.set_nodelay
。版本 3.1 中新增。
其他¶
客户端支持¶
- 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_options
和on_message_callback
。版本 4.5 中变更: 添加了
ping_interval
,ping_timeout
和max_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 连接。
code
和reason
在WebSocketHandler.close
中有说明。版本 3.2 中新增。
版本 4.0 中的变更: 添加了
code
和reason
参数。
- 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 中的新增内容。