tornado.websocket
— 與瀏覽器雙向通訊¶
WebSocket 協議的實作。
WebSockets 允許瀏覽器和伺服器之間的雙向通訊。所有主流瀏覽器的當前版本都支援 WebSockets。
此模組實作了 RFC 6455 中定義的最終版本 WebSocket 協議。
在 4.0 版本變更: 移除對 draft 76 協議版本的支援。
- class tornado.websocket.WebSocketHandler(application: Application, request: HTTPServerRequest, **kwargs: Any)[原始碼]¶
繼承此類別以建立基本的 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); };
此腳本會彈出一個警告框,顯示「You said: Hello, world」。
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]] [原始碼]¶
當新的 WebSocket 開啟時呼叫。
open
的參數是從tornado.web.URLSpec
正規表示式中擷取的,就像tornado.web.RequestHandler.get
的參數一樣。open
可以是協程。on_message
將在open
傳回之後才會被呼叫。在 5.1 版本變更:
open
可以是協程。
- WebSocketHandler.on_message(message: Union[str, bytes]) Optional[Awaitable[None]] [原始碼]¶
處理 WebSocket 上的傳入訊息
必須覆寫此方法。
在 4.5 版本變更:
on_message
可以是協程。
- WebSocketHandler.on_close() None [原始碼]¶
當 WebSocket 關閉時呼叫。
如果連線已正常關閉,且提供了狀態碼或原因短語,這些值將可作為屬性
self.close_code
和self.close_reason
使用。在 4.0 版本中變更:新增了
close_code
和close_reason
屬性。
- WebSocketHandler.select_subprotocol(subprotocols: List[str]) Optional[str] [原始碼]¶
覆寫此方法以實作子協定的協商。
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] [原始碼]¶
將指定訊息傳送給此 WebSocket 的客戶端。
訊息可以是字串或字典(將會編碼為 json)。如果
binary
引數為 false,則訊息將以 utf8 傳送;在二進位模式下,允許任何位元組字串。如果連線已關閉,則會引發
WebSocketClosedError
。傳回可用於流程控制的Future
。在 3.2 版本中變更:新增了
WebSocketClosedError
(先前關閉的連線會引發AttributeError
)。在 4.3 版本中變更:傳回可用於流程控制的
Future
。在 5.0 版本中變更:一致地引發
WebSocketClosedError
。先前有時會引發StreamClosedError
。
組態¶
- WebSocketHandler.check_origin(origin: str) bool [原始碼]¶
覆寫此方法以啟用對允許替代來源的支持。
origin
參數是Origin
HTTP 標頭的值,即啟動此請求的 URL。對於未傳送此標頭的客戶端,不會呼叫此方法;這些請求始終被允許(因為所有實作 WebSocket 的瀏覽器都支援此標頭,而且非瀏覽器客戶端沒有相同的跨網站安全考量)。應返回
True
以接受請求,或返回False
以拒絕請求。預設情況下,會拒絕所有來自非此主機的來源的請求。這是一種安全保護,可防止瀏覽器上的跨網站腳本攻擊,因為 WebSocket 允許繞過通常的同源策略,並且不使用 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]] [原始碼]¶
覆寫此方法以返回連線的壓縮選項。
如果此方法返回 None(預設值),則會停用壓縮。如果它返回一個字典(即使是空的),則會啟用壓縮。字典的內容可用於控制以下壓縮選項
compression_level
指定壓縮級別。mem_level
指定用於內部壓縮狀態的記憶體量。4.1 版本新增。
在 4.5 版本中變更:新增了
compression_level
和mem_level
。
- WebSocketHandler.set_nodelay(value: bool) None [原始碼]¶
為此串流設定無延遲標誌。
預設情況下,可能會延遲和/或合併小訊息,以盡量減少傳送的封包數量。由於 Nagle 演算法和 TCP 延遲 ACK 之間的交互作用,這有時會導致 200-500 毫秒的延遲。若要減少此延遲(可能會以增加頻寬使用量為代價),請在建立 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] [原始碼]¶
客戶端 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 [原始碼]¶
關閉 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] [原始碼]¶
傳送訊息到 WebSocket 伺服器。
如果串流已關閉,則會引發
WebSocketClosedError
。傳回一個Future
,可用於流程控制。在 5.0 版本變更: 在關閉的串流上引發的例外狀況,從
StreamClosedError
變更為WebSocketClosedError
。
- read_message(callback: Optional[Callable[[Future[Union[None, str, bytes]]], None]] = None) Awaitable[Union[None, str, bytes]] [原始碼]¶
從 WebSocket 伺服器讀取訊息。
如果在 WebSocket 初始化時指定了 on_message_callback,則此函數永遠不會回傳訊息。
返回一個 Future,其結果為訊息,如果連線關閉則返回 None。如果提供了 callback 參數,則會在 Future 準備好時使用該 Future 呼叫它。
- ping(data: bytes = b'') None [原始碼]¶
傳送 ping 框架到遠端。
data 參數允許傳送少量資料(最多 125 個位元組)作為 ping 訊息的一部分。請注意,並非所有 WebSocket 實作都會將此資料公開給應用程式。
請考慮使用
ping_interval
參數到websocket_connect
,而不是手動發送 ping。在 5.1 版本中新增。