Python Falcon 简明教程
Python Falcon - Websocket
WebSocket 是客户端与服务器之间的持久连接,可在这两者之间提供双向 full-duplex 通信。通信经由 HTTP 在单个 TCP/IP 套接字连接中发生。这可以看做是 HTTP 的升级,而不是一个协议本身。
A WebSocket is a persistent connection between a client and server to provide a bidirectional, full-duplex communication between the two. The communication takes place over HTTP through a single TCP/IP socket connection. It can be seen as an upgrade of HTTP instead of a protocol itself.
HTTP 的局限性之一是它是一个严格的半双工或单向协议。另一方面,借助 WebSocket,我们可以发送基于消息的数据(类似于 UDP),但借助 TCP 的可靠性。WebSocket 使用 HTTP 作为初始传输机制,但在收到 HTTP 响应后保持 TCP 连接的活动状态。可以将同一连接对象用于客户端和服务器之间的双向通信。因此,可以使用 WebSocket API 构建实时应用。
One of the limitations of HTTP is that it is a strictly half-duplex or unidirectional protocol. With WebSockets, on the other hand, we can send message-based data, similar to UDP, but with the reliability of TCP. WebSocket uses HTTP as the initial transport mechanism, but keeps the TCP connection alive the connection after the HTTP response is received. Same connection object it can be used two-way communication between client and server. Thus, real-time applications can be built using WebSocket APIs.
Falcon 的 Websocket 支持仅适用于 ASGI 应用。若要提供 Websocket 能力,资源类应具有 on_websocket() 回应器协程。
Falcon’s Websocket support is available only for ASGI applications. To provide Websocket capability, the resource class should have on_websocket() responder coroutine.
async def on_websocket(self, req, ws):
. . .
Websocket 请求还可由钩子和中间件拦截。将传递 falcon.asgi.WebSocket 对象,而不是 Response 对象。
Websocket requests can also be intercepted by hooks and middleware. Instead of the Response object, a falcon.asgi.WebSocket object is passed.
How Does a WebSocket Function in Falcon?
以下示例演示了 Falcon 应用中 WebSocket 的功能。首先,我们有一个 on_get() 回应器,它用来呈现一个模板。
The following example demonstrates the functioning of WebSocket in Falcon application. First we have an on_get() responder that renders a template.
Example
客户端浏览器显示一个带有文本字段和按钮的表单,单击该按钮时,就会创建一个 websocket 对象,并触发 on_websocket() 回应器。它接受用户输入的消息,并以“消息文本为”为前缀将它反馈给客户端。
The client browser displays a form with a text field and a button, When the button is clicked, a websocket object is created, and the on_websocket() responder is fired. It accepts the message input by the user and echoes it back to the client with a prefix “The message text was”.
import falcon
import falcon.asgi
import jinja2
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<script>
var ws = new WebSocket("ws://localhost:8000/hello");
ws.onmessage = function(event) {
var messages =document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'></ul>
</body>
</html>
"""
class HelloResource:
async def on_get(self, req, resp):
"""Handles GET requests"""
resp.status = falcon.HTTP_200
resp.content_type = 'text/html'
template=jinja2.Template(html)
resp.body=template.render()
async def on_websocket(self, req, websocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
app = falcon.asgi.App()
hello = HelloResource()
app.add_route('/hello', hello)
import uvicorn
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
Output
启动 Uvicorn 服务器,并访问 http://localhost:8000/ws URL 以显示聊天表单。
Start the Uvicorn server and visit http://localhost:8000/ws URL to display the chat form.

输入一些文本并按 Send 按钮。
Enter some text and press the Send button.
