WebSocket 是基于 HTTP 升级的长连接协议,浏览器和前端都支持得很好。
HTTP vs WebSocket
HTTP(传统请求响应)
- 浏览器:发一个请求 → 服务器:回一个响应 → 连接就结束了(短连接)。
- 如果要持续拿数据,就要不停地“轮询”:隔几秒再发一次 HTTP 请求。
WebSocket
- 一开始也是通过 HTTP 发起请求,但带上 Upgrade: websocket 头,请求“升级协议”。
- 服务器同意后,这条连接就从“普通 HTTP”升级为 WebSocket 长连接。
- 之后这条连接会一直保持(直到双方主动断开或异常断开)。客户端可以随时发消息给服务端。服务端也可以主动推消息给客户端(不像 HTTP 必须“等请求”)。
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| """ FastAPI 混合接口示例 """ from fastapi import FastAPI, WebSocket, WebSocketDisconnect from datetime import datetime
app = FastAPI(title="混合接口示例")
@app.get("/health") async def health(): """健康检查""" return {"status": "ok", "time": datetime.now().isoformat()}
@app.get("/api/info") async def get_info(): """获取信息""" return {"name": "测试服务", "version": "1.0"}
@app.post("/api/echo") async def echo(data: dict): """回显POST数据""" return {"received": data}
@app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): """WebSocket 回显""" await websocket.accept() print("WebSocket 已连接") try: while True: data = await websocket.receive_text() print(f"收到: {data}") await websocket.send_text(f"回复: {data}") except WebSocketDisconnect: print("WebSocket 已断开")
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8080)
|
客户端(脚本)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| """测试 WebSocket 连接""" import asyncio import websockets
async def test(): uri = "ws://localhost:8080/ws" print(f"连接到 {uri}") async with websockets.connect(uri) as ws: print("连接成功!") await ws.send("你好") print("已发送: 你好") response = await ws.recv() print(f"收到回复: {response}")
asyncio.run(test())
|
客户端(网页)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <!DOCTYPE html> <html> <head> <title>WebSocket 测试</title> <style> body { font-family: Arial; padding: 20px; } #log { background: #f0f0f0; padding: 10px; height: 200px; overflow-y: auto; margin: 10px 0; } input { padding: 8px; width: 300px; } button { padding: 8px 16px; margin-left: 5px; } </style> </head> <body> <h2>WebSocket 测试</h2> <div> <button onclick="connect()">连接</button> <button onclick="disconnect()">断开</button> </div> <div id="log"></div> <div> <input type="text" id="msg" placeholder="输入消息" value="你好"> <button onclick="send()">发送</button> </div>
<script> let ws = null; const log = (msg) => { document.getElementById('log').innerHTML += msg + '<br>'; };
function connect() { ws = new WebSocket('ws://localhost:8080/ws'); ws.onopen = () => log('✅ 已连接'); ws.onmessage = (e) => log('📩 收到: ' + e.data); ws.onclose = () => log('❌ 已断开'); ws.onerror = (e) => log('⚠️ 错误'); }
function disconnect() { if (ws) ws.close(); }
function send() { const msg = document.getElementById('msg').value; if (ws && ws.readyState === 1) { ws.send(msg); log('📤 发送: ' + msg); } else { log('⚠️ 未连接'); } } </script> </body> </html>
|