使用 Sanic 框架开发 Web 和 WebSocket 应用
Sanic 是一个基于 Python 的异步 Web 框架,以下是使用 Sanic
, json
, WebSocket
和 Request
的完整指南:
1. 安装 Sanic
首先安装 Sanic:
pip install sanic -i https://pypi.tuna.tsinghua.edu.cn/simple
推荐安装最新版本(当前 >=21.12+):
pip install --upgrade sanic -i https://pypi.tuna.tsinghua.edu.cn/simple
2. 基本 HTTP 服务器示例
from sanic import Sanic, json as jsonify, Request
app = Sanic("MyApp")
@app.route("/")
async def hello(request: Request):
return jsonify({"message": "Hello Sanic!"})
@app.route("/user/<user_id:int>")
async def get_user(request: Request, user_id: int):
return jsonify({"user_id": user_id, "name": "John"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
3. WebSocket 示例
from sanic import Websocket
@app.websocket("/ws")
async def chat(request: Request, ws: Websocket):
while True:
data = await ws.recv()
await ws.send(f"Server received: {data}")
4. 完整功能示例
from sanic import Sanic, json as jsonify, Websocket, Request
from sanic.response import text
app = Sanic("AdvancedExample")
# 中间件示例
@app.middleware("request")
async def auth_middleware(request: Request):
if request.token != "secret":
return jsonify({"error": "Unauthorized"}, status=401)
# REST API 路由
@app.route("/api/data", methods=["GET", "POST"])
async def handle_data(request: Request):
if request.method == "GET":
return jsonify({"data": [1, 2, 3]})
# POST 请求处理
payload = request.json
return jsonify({"received": payload}, status=201)
# WebSocket 聊天室
@app.websocket("/chat")
async def chat_handler(request: Request, ws: Websocket):
await ws.send("Welcome to chat room!")
while True:
message = await ws.recv()
if message == "exit":
break
await ws.send(f"You said: {message}")
# 文件上传
@app.route("/upload", methods=["POST"])
async def upload_file(request: Request):
upload_file = request.files.get("file")
if upload_file:
return text(f"Received {upload_file.name}")
return text("No file uploaded", status=400)
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=8000,
workers=4,
access_log=True,
debug=True
)
5. 关键组件详解
5.1 Request 对象
@app.route("/info") async def show_request_info(request: Request): return jsonify({ "method": request.method, "url": request.url, "headers": dict(request.headers), "query": request.args, "body": request.json # 自动解析 JSON 体 })
5.2 WebSocket 通信
@app.websocket("/echo") async def echo_server(request: Request, ws: Websocket): async for msg in ws: if msg == "ping": await ws.send("pong") else: await ws.send(f"Echo: {msg}")
5.3 JSON 响应
@app.route("/user") async def get_current_user(request: Request): user = { "id": 123, "name": "Alice", "email": "alice@example.com" } return jsonify(user, status=200, headers={"X-Custom": "value"})
6. 高级功能
6.1 蓝图 (Blueprints)
from sanic import Blueprint auth_bp = Blueprint("auth", url_prefix="/auth") @auth_bp.route("/login") async def login(request: Request): return jsonify({"token": "abc123"}) app.blueprint(auth_bp)
6.2 后台任务
@app.route("/start-task") async def start_task(request: Request): async def background_task(): await asyncio.sleep(10) print("Task completed") request.add_task(background_task) return text("Task started")
6.3 信号处理
from sanic.signals import Event @app.signal(Event.HTTP_LIFECYCLE_BEGIN) async def on_request_start(request: Request): print(f"Request started: {request.url}")
7. 运行与部署
开发模式运行:
python app.py
生产部署(使用 sanic CLI):
sanic app:app --host=0.0.0.0 --port=8000 --workers=8
使用 Gunicorn(多进程):
gunicorn app:app --worker-class sanic.worker.GunicornWorker
8. 注意事项
-
异步上下文:所有处理函数必须是
async
函数 -
Python 版本:需要 Python 3.8+
-
性能调优:
-
调整
workers
数量(通常为 CPU 核心数) -
对于 CPU 密集型任务,考虑使用
uvloop
:pip install uvloop
然后在代码中添加:
app.run(..., fast=True)
-
Sanic 是构建高性能 Python Web 应用的优秀选择,特别适合需要异步处理和 WebSocket 功能的场景。
使用 jsonrpc 库实现 JSON-RPC 服务
jsonrpc
是一个用于实现 JSON-RPC 2.0 协议的 Python 库。
1. 安装 jsonrpc 库
pip install jsonrpcclient jsonrpcserver -i https://pypi.tuna.tsinghua.edu.cn/simple
或者安装经典版本(不推荐,可能不兼容 Python 3.10+):
pip install jsonrpc==1.12.3 -i https://pypi.tuna.tsinghua.edu.cn/simple
2. 基本服务端实现
from jsonrpc import JSONRPCResponseManager, Dispatcher
from werkzeug.wrappers import Request, Response
# 创建方法调度器
dispatcher = Dispatcher()
# 注册方法
@dispatcher.add_method
def add(a, b):
return a + b
@dispatcher.add_method
def greet(name):
return f"Hello, {name}!"
# 创建JSON-RPC服务端点
@Request.application
def application(request):
response = JSONRPCResponseManager.handle(
request.data, dispatcher
)
return Response(response.json, mimetype='application/json')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)
3. 现代实现方式(推荐)
3.1 使用 jsonrpcserver
from jsonrpcserver import method, serve @method def add(a, b): return a + b @method def greet(name): return f"Hello, {name}!" if __name__ == "__main__": serve(port=5000)
3.2 异步版本
from jsonrpcserver import method, async_dispatch
from aiohttp import web
@method
async def add(a, b):
return a + b
async def handle(request):
return web.Response(
text=await async_dispatch(await request.text()),
content_type="application/json"
)
app = web.Application()
app.router.add_post("/", handle)
web.run_app(app, port=5000)
4. 客户端实现
4.1 基本客户端
import requests
import json
def rpc_call(url, method, params=None):
payload = {
"jsonrpc": "2.0",
"method": method,
"params": params or [],
"id": 1
}
response = requests.post(url, json=payload).json()
return response.get("result")
# 使用示例
result = rpc_call("http://localhost:4000", "add", [2, 3])
print(result) # 输出: 5
4.2 使用 jsonrpcclient
from jsonrpcclient import request response = request("http://localhost:4000", "greet", {"name": "Alice"}) print(response.data.result) # 输出: "Hello, Alice!"
5. 高级功能
5.1 错误处理
from jsonrpc import JSONRPCResponseManager, Dispatcher from jsonrpc.exceptions import JSONRPCDispatchException dispatcher = Dispatcher() @dispatcher.add_method def divide(a, b): if b == 0: raise JSONRPCDispatchException( code=-32000, message="Division by zero", data={"param_b": b} ) return a / b
5.2 批量请求
batch_request = [ {"jsonrpc": "2.0", "method": "add", "params": [2, 3], "id": 1}, {"jsonrpc": "2.0", "method": "greet", "params": ["Bob"], "id": 2} ] response = requests.post("http://localhost:4000", json=batch_request).json()
6. 与 Web 框架集成
6.1 Flask 集成
from flask import Flask, request from jsonrpc import JSONRPCResponseManager app = Flask(__name__) @app.route("/api", methods=["POST"]) def rpc_server(): manager = JSONRPCResponseManager() return manager.handle(request.data, dispatcher)
6.2 Sanic 集成
from sanic import Sanic, json from jsonrpc import JSONRPCResponseManager app = Sanic("RPCService") @app.post("/api") async def rpc_handler(request): manager = JSONRPCResponseManager() response = manager.handle(request.body, dispatcher) return json(response.data)
7. 注意事项
-
版本兼容性:
-
经典
jsonrpc
库 (1.x) 可能不兼容 Python 3.10+ -
推荐使用
jsonrpcserver
和jsonrpcclient
替代
-
-
安全性:
-
始终验证输入参数
-
考虑添加认证中间件
-
-
性能优化:
-
对于高负载服务,考虑使用异步实现
-
使用连接池管理客户端连接
-
-
调试工具:
-
使用 Postman 或 curl 测试端点:
curl -X POST http://localhost:4000 \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"add","params":[2,3],"id":1}'
-
JSON-RPC 是构建轻量级 API 服务的优秀协议,特别适合需要简单、标准化通信的场景。