随着 CPython3.6 的发布,asyncio(异步 io 标准库)的 API 正式稳定下来了, 无疑利用 asyncio 写 web 应用将会极为方便。 虽然 python 现有已经存在一些异步 IO 网络框架(twisted, tornado, gevent), 但它们都不能很好的利用 python3 的新特性(比如 async/await 关键字), 所以决定尝试一下 aiohttp 的 web 框架。
安装
pip install aiohttp
hello world
虽然 aiohttp 经常用于客户端编程,但是它也可以用于服务端 web 开发, 而且写法也极为优美,下面是一个 hello world 示例:
from aiohttp import web
async def hello(request):
name = request.match_info.get('name', 'Anonymous')
text = f'Hello, {name}'
return web.Response(text=text)
app = web.Application()
app.router.add_get('/', hello)
app.router.add_get('/{name}', hello)
web.run_app(app)
websocket
aiohttp 也原生支持 websocket:
from aiohttp import web
async def ws_hello(request):
ws = web.WebSocketResponse()
await ws.prepare(request)
async for msg in ws:
if msg.type == web.MsgType.text:
ws.send_str(f'Hello, {msg.data}')
elif msg.type == web.MsgType.binary:
ws.send_bytes(msg.data)
elif msg.type == web.MsgType.close:
break
return ws
app = web.Application()
app.router.add_get('/echo', ws_hello)
web.run_app(app)
目录结构
虽然写一个简单的 web 服务一个文件就可以了, 但是当 web 服务比较复杂时,清晰的目录结构可以更有效的组织代码, 自己写一个服务时利用了以下代码结构:
backend
├── app/
│ ├── model/
│ ├── sql/
│ ├── api/
│ ├── config.py
│ ├── db.py
│ ├── middlewares.py
│ ├── permissions.py
│ ├── urls.py
│ └── utils.py
├── requirements/
│ ├── base.txt
│ ├── dev.txt
│ └── prod.txt
├── tests/
├── init/
├── deploy/
├── run.py
└── README.md
其中:
app
目录存放所有服务相关的代码app/model
目录存放服务相关的 model 定义app/sql
目录存放数据库表格定义/修改的 sql 脚本app/config.py
存放所有相关配置信息app/db.py
存放与数据库操作与初始化相关的代码app/middlewares.py
存放 web 服务的中间件app/permissions.py
存放与权限检测相关的代码app/urls.py
存放 web 服务的路由定义app/utils.py
存放一些辅助工具函数requirements
目录存放 pip 安装 requirements 文件init
目录提供一些与数据库初始化和测试样例数据初始化的代码deploy
目录存放与服务部署相关的代码run.py
是服务的入口脚本,与flask-cli
类似
相关包
asyncio 周边已经存在大量辅助包了,这里列一些比较常用的包:
- uvloop
- aiofiles
- asyncpg
- aioredis
- aiokafka
- aioes