比 FastAPI 更轻量:Starlette 源码深挖 + 手写高性能接口网关(含请求鉴权、限流)
比 FastAPI 更轻量:Starlette 源码深挖 + 手写高性能接口网关(含请求鉴权、限流)
前言:如今 Python 后端领域,FastAPI 早已成为主流选择,各类“从入门到精通”教程泛滥成灾,但很少有人关注其底层核心依赖——Starlette。作为一款轻量级 ASGI 框架/工具包,Starlette 是 FastAPI 高性能的基石,它无冗余依赖、支持异步、原生兼容 WebSocket,更适合用来构建轻量、高性能的接口网关。本文将避开 FastAPI 烂大街的知识点,深挖 Starlette 核心源码(路由、中间件、WebSocket),拆解其设计精髓,最终手把手实战手写一款支持请求鉴权、流量限流的高性能接口网关,兼顾原理剖析与落地实战,全程干货,适合有一定 Python 异步编程基础、想深入底层源码、提升架构能力的开发者。
核心收获:掌握 Starlette 三大核心机制的源码逻辑、理解 Starlette 与 FastAPI 的底层关联、学会手写轻量接口网关、掌握网关核心功能(鉴权、限流)的实现方式,避开同类教程的同质化陷阱。
一、先搞懂:Starlette 是什么?为什么比 FastAPI 更轻量?
在深挖源码之前,我们先明确 Starlette 的定位——它不是 FastAPI 的“替代品”,而是 FastAPI 的“底层骨架”。很多开发者误以为 FastAPI 的高性能源于其自身设计,实则不然:FastAPI 的核心异步能力、路由分发、请求响应处理,全部依赖 Starlette,而 FastAPI 在此基础上新增了 Pydantic 类型校验、自动接口文档(OpenAPI)等上层功能,这也导致其冗余度更高、体积更大。
1.1 Starlette 核心定位与特性
Starlette 官方定义是“轻量级 ASGI 框架/工具包”,核心特性的可以总结为 4 点,这也是它“轻量且高性能”的关键:
无冗余依赖:核心代码仅依赖 Python 标准库,额外功能(如模板、表单处理)需手动安装,按需引入,避免“用不上但必须加载”的冗余。
原生异步支持:基于 ASGI 标准开发,完美支持 async/await 语法,异步性能比肩 Node.js、Go 框架,远优于 Flask 等同步框架。
功能精简且强大:核心功能仅包含路由、中间件、WebSocket、请求/响应处理,无多余封装,可灵活扩展,适合构建网关、微服务接口等场景。
100% 类型注解:源码全程使用类型注解,可读性强,便于二次开发和维护,这也是 FastAPI 能实现自动类型校验的基础之一。
用一句通俗的话总结:Starlette 是“极简版的异步 Web 框架骨架”,而 FastAPI 是“基于这个骨架封装的完整版框架”。如果你的场景不需要自动接口文档、复杂类型校验,Starlette 会是更轻量、更高效的选择——比如接口网关,核心需求是路由转发、鉴权、限流,无需多余上层功能,Starlette 恰好契合。
1.2 Starlette 与 FastAPI 的底层关联(源码视角)
我们从源码层面拆解两者的关系:FastAPI 的核心类FastAPI本质上是Starlette类的子类,它继承了 Starlette 的所有核心能力,再新增自身的功能。
FastAPI 源码核心片段(简化版):
fromstarlette.applicationsimportStarlettefromstarlette.routingimportRoute,WebSocketRouteclassFastAPI(Starlette):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)# 新增 Pydantic 类型校验相关逻辑self.openapi_schema={}self.dependency_overrides={}# 新增自动接口文档相关逻辑self.add_route("/docs",self.docs)self.add_route("/redoc",self.redoc)从这段代码可以清晰看出:FastAPI 完全复用了 Starlette 的路由、中间件等核心机制,只是在其基础上增加了 OpenAPI 文档、依赖注入、类型校验等上层功能。这也意味着,掌握了 Starlette,就等于掌握了 FastAPI 的底层核心,反之则不然——很多 FastAPI 开发者,对其底层的 Starlette 机制一无所知。
1.3 为什么选择 Starlette 手写接口网关?
接口网关的核心需求是“轻量、高性能、可扩展”,而 Starlette 恰好完美契合这三个需求:
轻量:无冗余依赖,启动速度快,内存占用低,适合部署在网关这类需要高并发、低延迟的场景(对比 FastAPI,启动速度提升 30%+,内存占用降低 40%+)。
高性能:原生异步支持,基于 ASGI 标准,可处理每秒万级请求,远超 Flask 等同步框架,甚至在高并发场景下,性能接近 FastAPI(无额外功能损耗)。
可扩展:中间件机制灵活,可轻松集成鉴权、限流、日志、监控等网关核心功能,路由转发逻辑简洁,便于定制化开发。
此外,CSDN 上关于 Starlette 源码解析的文章极少,大部分教程都聚焦于 FastAPI 的上层使用,导致很多开发者对这个“底层基石”了解甚少,这也正是本文的核心价值——深挖 Starlette 源码,用它手写可落地的接口网关,避开同质化陷阱。
二、Starlette 核心源码深挖(三大核心机制)
Starlette 的核心源码集中在三个模块:routing(路由)、middleware(中间件)、websockets(WebSocket)。这三个模块是 Starlette 的灵魂,也是我们手写网关的核心依赖。本节将逐一看透其源码逻辑,不堆砌冗余代码,只抓核心设计。
2.1 路由机制:Starlette 如何实现高效路由分发?(源码核心)
路由是 Web 框架的基础,负责将请求映射到对应的处理函数。Starlette 的路由机制简洁高效,支持路径参数、正则路由、WebSocket 路由,其核心源码在starlette/routing.py中,核心类是Router和Route。
2.1.1 核心类设计(源码简化剖析)
首先看Route类,它负责定义单个路由规则,核心是“路径匹配 + 处理函数绑定”:
# starlette/routing.py 核心片段(简化)classRoute:def__init__(self,path:str,endpoint:Callable,methods:Optional[List[str]]=None):self.path=path# 路由路径,如 "/api/user"self.endpoint=endpoint# 路由处理函数(可异步)self.methods=methodsor["GET"]# 支持的请求方法# 路径匹配器,将路径转换为正则表达式,用于匹配请求路径self.path_regex,self.path_params=compile_path(path)asyncdefhandle(self,request:Request)->Response:# 调用处理函数,返回响应ifasyncio.iscoroutinefunction(self.endpoint):returnawaitself.endpoint(request)# 异步处理函数else:returnself.endpoint(request)# 同步处理函数核心亮点:compile_path函数将路由路径(如"/api/user/{user_id}")编译为正则表达式,同时提取路径参数(如user_id),这也是 Starlette 支持路径参数的核心。
再看Router类,它负责管理所有路由,实现路由分发:
# starlette/routing.py 核心片段(简化)classRouter:def__init__(self,routes:Optional[List[BaseRoute]]=None):self.routes=routesor[]# 存储所有路由规则# 按请求方法分组路由,提升匹配效率(避免遍历所有路由)self.routes_by_method:Dict[str,List[Route]]=defaultdict(list)forrouteinself.routes:formethodinroute.methods:self.routes_by_method[method.upper()].append(route)asyncdefroute(self,request:Request)->Response:# 1. 获取请求方法和路径method=request.method.upper()path=request.url.path# 2. 匹配对应的路由(按方法分组,提升效率)forrouteinself.routes_by_method.get(method,[]):match=route.path_regex.match(path)ifmatch:# 提取路径参数,注入到请求对象中request.path_params=match.groupdict()# 调用路由的处理函数,返回响应returnawaitroute.handle(request)# 3. 无匹配路由,返回 404returnResponse(status_code=404,content="Not Found")2.1.2 路由分发核心逻辑(关键)
Starlette 路由分发的核心逻辑的是“按方法分组 + 正则匹配”,步骤如下:
初始化 Router 时,将所有路由按请求方法(GET、POST 等)分组,存储在
routes_by_method中,避免每次请求都遍历所有路由。当请求到来时,先获取请求方法和路径,从对应方法的路由列表中遍历匹配。
通过路由的
path_regex(编译后的正则)匹配请求路径,匹配成功则提取路径参数,调用对应的处理函数。无匹配路由时,返回 404 响应。
优势:按方法分组减少了遍历次数,正则匹配高效,支持异步处理函数,整体性能优异——这也是 FastAPI 路由分发高效的底层原因。
2.2 中间件机制:Starlette 如何实现请求/响应拦截?
中间件是接口网关的核心组件,负责拦截请求、处理通用逻辑(如鉴权、限流、日志),Starlette 的中间件机制简洁灵活,支持链式调用,核心源码在starlette/middleware/__init__.py中,核心类是Middleware和BaseHTTPMiddleware。
2.2.1 中间件核心设计(源码剖析)
Starlette 的中间件本质是“装饰器模式”,每个中间件都包裹着下一个中间件或路由处理函数,形成链式调用。先看BaseHTTPMiddleware(所有中间件的基类):
# starlette/middleware/__init__.py 核心片段classBaseHTTPMiddleware:def__init__(self,app:ASGIApp):self.app=app# 下一个中间件或路由处理函数(ASGI 应用)asyncdef__call__(self,scope:Scope,receive:Receive,send