# Starlette一个被低估的异步Web框架它到底是什么先说说Starlette的身份。很多人第一次接触它可能是在FastAPI的文档里——FastAPI的底层就是Starlette。但Starlette自己本身就是一个完整的异步Web框架不是FastAPI的附属品。它的核心定位是一个轻量级的、高性能的ASGI框架。ASGI是Python异步Web的新标准可以理解为WSGI的升级版。WSGI时代Django、Flask处理请求是同步的一个请求来了得等它处理完才能处理下一个。ASGI就不一样了一个请求在处理过程中可以切换到其他请求就像你在排队时能同时发微信、刷微博一样。Starlette的设计哲学很有意思。它不像Django那样“飞机杯”式的什么都给你配好也不像Flask那样过于简单很多东西得自己拼凑。Starlette更像是给开发者一套高质量的工具箱里面装着最好的螺丝刀、扳手但怎么组装成一个完整的应用得你自己来。它能做什么不能做什么先说说能做什么。Web应用开发这是最基本的。RESTful API、WebSocket实时通信、模板渲染这些它都支持。而且因为基于ASGI天然就支持异步处理。举个例子你写个文件上传功能用Starlette可以在等待文件写入时处理其他请求而不用让整个服务器卡住。微服务搭建Starlette很轻启动快资源占用少特别适合作为微服务的骨架。一个服务可能只需要处理几个API用Django太重了用Flask又缺少一些底层支持Starlette就刚好。API网关/代理它的Request和Response对象设计得很灵活你可以很容易地修改请求或响应加上鉴权、日志、限流等功能。很多人用它做API网关在请求到达真正的服务之前做一层处理。实时Web应用WebSocket的支持是原生、完整的。聊天系统、实时通知、协作编辑这些场景Starlette表现得相当好。它的WebSocket处理方式和HTTP请求处理方式很统一学习成本很低。但也有些场景它不太适合。如果你的项目需要一个成熟的管理后台、ORM、表单验证、模板标签库Starlette默认不给这些。当然你可以自己加但那会让代码变得很臃肿。这种时候还是选Django更合适。怎么上手使用安装很简单pipinstallstarlette不过实际开发通常还需要加个ASGI服务器最常用的是Uvicornpipinstalluvicorn一个最小的应用大概长这样fromstarlette.applicationsimportStarlettefromstarlette.responsesimportJSONResponsefromstarlette.routingimportRouteasyncdefhomepage(request):returnJSONResponse({message:Hello World})appStarlette(debugTrue,routes[Route(/,endpointhomepage),])启动也很简单uvicorn main:app这里要注意的是Starlette的应用实例本身就是一个可调用的ASGI应用。你可以直接用Uvicorn、Daphne或Hypercorn等服务器来运行它。写一个带路径参数的APIasyncdefuser_detail(request):user_idrequest.path_params[user_id]# 这里可以异步查询数据库returnJSONResponse({user_id:user_id})Route(/users/{user_id:int},endpointuser_detail)WebSocket的例子也很直接fromstarlette.websocketsimportWebSocketasyncdefwebsocket_endpoint(websocket):awaitwebsocket.accept()whileTrue:dataawaitwebsocket.receive_text()awaitwebsocket.send_text(f你已经说了:{data})它的中间件机制也值得一说。很多框架的中间件是洋葱圈模型请求一层层穿过去响应一层层穿回来。Starlette的中间件也是类似的但实现方式更接近ASGI本身的工作原理写起来感觉很通透。fromstarlette.middleware.baseimportBaseHTTPMiddlewareclassCustomHeaderMiddleware(BaseHTTPMiddleware):asyncdefdispatch(self,request,call_next):# 请求进来时做的操作start_timetime.time()responseawaitcall_next(request)# 响应出去时做的操作process_timetime.time()-start_time response.headers[X-Process-Time]str(process_time)returnresponse一些实践经验说说实际开发中怎么用好Starlette。关于项目结构不要太分散也别挤在一起。我一般会按功能模块分文件夹每个模块里有routes.py路由定义、views.py处理逻辑、models.py数据模型。因为Starlette本身很自由所以需要自己约束项目结构。参考Django的app结构是个不错的起点。关于依赖注入Starlette没有自带依赖注入系统但它的Request对象提供了一个state属性可以在请求过程中共享数据。比如在中间件里从数据库加载用户信息存到request.state.user里后面的视图函数直接取用。关于数据库Starlette不关心你用ORM还是原生SQL。但既然用异步框架数据库驱动最好也是异步的。推荐SQLAlchemy 1.4的异步模式或者直接上Tortoise ORM专门为异步框架设计的ORM。用同步数据库驱动的话得用线程池跑有点浪费异步的好处。关于错误处理可以写一个统一的异常处理器。比如定义一些自定义异常类NotFoundException、PermissionDenied等然后在应用级别注册对应的处理器。这样代码会很干净。fromstarlette.exceptionsimportHTTPExceptionfromstarlette.requestsimportRequestfromstarlette.responsesimportJSONResponseasyncdefnot_found_handler(request:Request,exc:HTTPException):returnJSONResponse({detail:资源不存在},status_code404)app.add_exception_handler(404,not_found_handler)关于性能因为Starlette本身很轻性能瓶颈通常不在框架而在I/O等待数据库、外部API调用。用异步写法可以很好地利用这段时间但要注意不要阻塞事件循环。比如用time.sleep()而不是asyncio.sleep()在异步代码里是致命的。和同类技术的比较拿Django来比就像拿全自动洗衣机对比手洗。Django什么都帮你做了但启动慢、占内存多、配置复杂。Starlette让你自己来但给你最好的工具。如果你的项目需要管理后台、需要ORM、需要成熟的模板系统选Django没错。如果项目主要是API或者需要高性能的WebSocket或者做的是微服务Starlette更合适。Flask是最常被拿来对比的。Flask的生态更大插件更丰富但它的同步模型限制了很多场景。Starlette是异步的在高并发场景下表现更好。Flask的请求处理是阻塞的一个请求如果卡在数据库查询上整个worker都被占着。Starlette可以在等待数据库响应时切换到其他请求。不过如果业务逻辑主要是在CPU上计算不是I/O等待那Flask和Starlette的性能差距就很小了。FastAPI和Starlette的关系比较特殊。FastAPI是建立在Starlette之上的它把Starlette的高级特性包装成更容易使用的API最重要的是加上了自动生成OpenAPI文档和请求验证。如果你需要这些功能直接上FastAPI就好它完全可以用Starlette的全部特性。但如果你想完全控制或者不想引入Pydantic的依赖用纯Starlette会更灵活。有几个生态上的选择也值得提Sanic、Quart、BlackSheep。Sanic是最早的异步Python Web框架但发展过程中走过弯路。Quart是Flask的异步版用法和Flask很像迁移成本低。BlackSheep性能更好但对微软的.NET风格偏好的开发者更友好。说到底选框架就像选工具没有绝对的好坏。Starlette的好处是它没有太多自己的“哲学”就是把ASGI这套标准实现得很干净、很好用。用了一段时间后会发现它不会拖你后腿也不会限制你应该怎么做事。这种“无感”的体验恰恰是一个好框架该有的样子。