前面我們學習了非同步web框架(sanic)和http非同步呼叫庫httpx,今天我們學習websocket技術。
websocket簡介
我們知道HTTP協議是:請求->響應,如果沒有響應就一直等著,直到超時;但是有時候後臺的處理需要很長時間才能給到結果,比如30分鐘,那HTTP的請求不可能等這麼久,所以,可以通過 Ajax 輪詢來解決。那就是每間隔一段時間就請求一次。
這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向伺服器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的資料可能只是很小的一部分,顯然這樣會浪費很多的頻寬等資源。
HTML5 定義的 WebSocket 協議,能更好的節省伺服器資源和頻寬,並且能夠更實時地進行通訊。
瀏覽器通過 JavaScript 向伺服器發出建立 WebSocket 連線的請求,連線建立以後,客戶端和伺服器端就可以通過 TCP 連線直接交換資料。
好了,WebSocket就是為了解決這個問題的,感興趣去看其他資料!
智慧聊天機器人
我一開始只是為了學習WebSocket找個例子,不少例子使用了聊天功能。我稍加改進就變成了智慧聊天功能了。
通過非同步sanic非同步框架實現Web功能。官方文件裡面給個WebSocket使用的例子。
https://sanic.readthedocs.io/en/latest/sanic/websocket.html
snaic部分核心程式碼如下:
import sanic
import httpx
from sanic import Sanic
from sanic.response import json
from sanic.websocket import WebSocketProtocol
from sanic.exceptions import NotFound
from sanic.response import html
from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('app', 'templates'))
app = Sanic(__name__)
@app.route('/')
async def index(request):
"""
聊天頁面
"""
template = env.get_template('index.html')
html_content = template.render(title='聊天機器人')
return html(html_content)
@app.websocket('/chat')
async def chat(request, ws):
"""
處理聊天資訊,並返回訊息
"""
while True:
user_msg = await ws.recv()
print('Received: ' + user_msg)
intelligence_data = {"key": "free", "appid": 0, "msg": user_msg}
r = httpx.get("http://api.qingyunke.com/api.php", params=intelligence_data)
chat_msg = r.json()["content"]
print('Sending: ' + chat_msg)
await ws.send(chat_msg)
if __name__ == "__main__":
app.error_handler.add(
NotFound,
lambda r, e: sanic.response.empty(status=404)
)
app.run(host="192.168.0.7", port=8000, protocol=WebSocketProtocol, debug=True)
- index() 函式,返回聊天頁面。這裡用到了jinja2 模板渲染庫。
- chat() 函式,通過webSocket實現訊息的接收、處理和返回。
智慧聊天是怎麼做到的,這裡要感謝 青雲客網路,他們提供了免費的介面。(我當時也只是抱著試試看的態度,沒想到,duang~! )
user_msg = "你好!"
intelligence_data = {"key": "free", "appid": 0, "msg": user_msg}
r = httpx.get("http://api.qingyunke.com/api.php", params=intelligence_data)
chat_msg = r.json()["content"]
print(chat_msg)
是不是超簡單。
再來看前端程式碼,主要部分:
<div class="container theme-showcase" role="main" style="margin-top: 80px;">
<div id="contents" style="height: 600px; background-color:#eee;"></div>
<div>
<textarea class="form-control" id="msg"></textarea>
<button class="btn btn-lg btn-info" onclick="sendMsg()" style="float: right;">傳送</button>
</div>
</div>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
var ws = new WebSocket("ws://192.168.0.7:8000/chat");
ws.onmessage = function(e) {
$("#contents").append('<div class="alert alert-info" role="alert" style="float: left;">' + "機器人: " + e.data + "</div><br><br><br><br>");
}
function sendMsg() {
var msg = $("#msg").val();
$("#contents").append('<div class="alert alert-info" role="alert" style="float:right">' + msg + "</div><br><br><br><br>");
ws.send(msg);
$("#msg").val("");
}
</script>
這裡使用到了 bootstrap 前端框架,主要 呼叫部分在:
var Socket = new WebSocket(url, [protocol] );
- Socket.send(msg): 使用連線傳送資料。
- Socket.onmessage: 客戶端接收服務端資料時觸發。
我知道,你迫不及待想要完整的程式碼了: