周末搜索一些信息时发现2023年还有不少人推荐使用Flask作为Python的Web框架,而我已经认为「Flask已死,FastAPI是未来」,所以写下本文,欢迎讨论和反驳。
Flask是一个在Python开发者心目中十分重要的项目,如果你是一个Web开发者,我相信你一定用过Flask,但是可能没有用过FastAPI。这个和国外相比可能会更明显一点,我觉得主要是因为国内已经没有多少人在写技术文章推荐,教大家分辨趋势或者主流,而一些老手即便知道它们的优缺点可能也懒得写对比文章,结果造成很多新人不了解怎么选,只能看一些老的文章、大V或者书籍的推荐作为选择的依据。
但是如果你有兴趣,你可以考证2点:
接着看一下Python官方的开发者调查中Web框架占比的变化:
可以看到19年FastAPI甚至不是一个选项,而22年已经占到25%的比率。这个开发者调查需要年中才会统计出上一年的,所以2023年的得明天第三季度才能知道,我预计FastAPI可以达到35%左右。
需要注意这个占比数据包含了现有系统,所以Django和Flask不容易跌得很快,但是趋势是很明显的。
我们知道Web框架这个领域是很高产的,基本每年都有新的框架诞生,大部分框架昙花一现,但有的框架却能够长青。FastAPI诞生于2018年底,在2019年年底左右开始崭露头角,那么为什么它可以在短短的5年里让关注度超过在2010年底诞生的Flask呢?接着我们顺着时间线捋捋Python Web框架和相关解决方案的发展来理解吧。
FastAPI作者是一个非常关注Python生态发展的开发者,延伸阅读链接2是一篇作者写的<Alternatives, Inspiration and Comparisons>,详细的介绍了FastAPI出各个库中的借鉴或者启发的细节,而发展史这部分我也参考了这篇文章。大家应该看看原文,里面包含了为什么会出现FastAPI以及作者的一些设计哲学。
Django是Python社区里最早做到统治级别的Web框架,当时知名的Instagram就是用它构建的。它的特点是大而全,各种web开发需要用到的细节它基本都有相关的模块,尤其和关系数据库、管理功能等方面耦合度非常高。对于熟悉的老手,这是一个生产级别的框架,但即便有完整的文档,对于初学者非常不友好,学习曲线中后期很陡峭,它的复杂度和定制成本非常高。
其实我这篇文章,也可以叫做「Django和Flask之死」,但是在框架应用场景角度来说Flask和FastAPI对比更合适,而Django直接和FastAPI相比有一些差别。在一些商业场景(例如CMS)Django依然是首选,而Flask(甚至FastAPI)看起来更像个「玩具」,所以Django短时间不会被取代(Flask这些年不是也是没取代的了嘛)。
Django主旨是为了在后端生成 HTML,而不是创建现代前端(如 React、Vue.js )或与其通信的其他系统使用的 API。所以FastAPI其实和Django REST Framework直接对标,它们主要场景都是构建 Web API,但是名字上也可以看出来,DRF还是依托于Django框架,所以缺点一样。
Flask是一个「微」框架(Micro framework),和Django截然相反,它仅保留小部分的核心,还为了解耦把功能拆分成几个库(如Jinja2,Werkzeug等),所以开发者有足够的自由,你可以很容易写出相关功能的第三方插件。它里面的蓝图、上下文、装饰器表示路由、信号等等设计在当时是非常先进的,再加上文档写的很完整,可以说对新手极为友好。
由于Flask的简单性,它非常适合构建API,不过由于Flask什么也不带,我们需要专门的REST框架。所以相继出现了 flask-restful 、Flask-RESTPlus、flask-api等框架,另外在Rest服务中,会需要数据验证、解析和规范等需要,也出现了Marshmallow、Webargs和APISpec,一直到Flask-apispec。但是整个发展过程中没有出现一个足够好的能够对标DRF的Flask REST Framework。
而到这个阶段,Flask的缺点其实也暴露了。
Flask本来的优点是灵活性和极简主义,但这意味着很多很多组件需要自己造,这个要不然需要公司够大专门有开发者开发和维护,要不然得个人能力极强,否则插件很难达到生产级别,这就造成Flask的第三方插件质量层次不齐,且无法保证长期维护。就像我上面说的那些库,现在来看,其中已经很多不再维护了。
所以即便是今天,你想用Flask构建一个API服务,还是要东拼西凑各个组件,其中某些组件有些没及时更新的地方要自己动手解决,这对于老手来说还好,对于新人来说很痛苦,尤其是你想要应用现在最新的实践方案和理念,只能望而兴叹。
从Python3.5开始,asyncio已经是未来的趋势了。所以开始出现了一些原生支持asyncio的Web框架,如aiohttp、Starlette和sanic。
这个时候Flask并不想接受改变,社区迟迟的不加入aio的支持,另外Flask原作者也去写rust了,把项目交给了2个维护者(现在只剩一个人了)。
而用于构架API服务的项目例如apistar,molten。它们都给FastAPI的带来了设计灵感。
接着就是诞生FastAPI了。作者本来也是想找到一个好的解决方案,但是以上种种都是自己的问题或者说局限性,所以作者就造了这个轮子。
这篇文章的核心部分啦,这些理由也是为什么FastAPI会替代Flask的原因。
在Flask的那个时代,代码执行是单线程、同步的,这意味着要依次处理请求,前一个请求完成前,其他请求消耗在等待 I/O 操作上。而asyncio是最好的解决方案,它让I/O成为异步操作,无需等待任务完成即可获取任务结果并继续处理其他任务请求。
而FastAPI天生支持并发和异步代码,代码写对了就可以在效率上达到极致,所以它被认为是目前最快的Python框架,效率和NodeJS或Go接近。当速度和性能至关重要时,FastAPI 是最佳选择。
API开发中数据格式的验证、解析和序列化是很常用的,在这些年的发展过程中出了很多种方案,而目前最好的方案就是Pydantic:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
这个代码初看是ORM/dataclass的写法,其实是基于Python原生的Type Hints的语法给字段做类型注解,例如上例的/items/
请求中的Item的schema已经定义好了,各个字段的值类型非常明确。和过去用schema描述甚至硬代码的方式相比很干净很pythonic,对于IDE支持也更好。
在现阶段,Pydantic在用户数据验证等领域是统治级别的,而FastAPI内置了它,这可以大大简化了验证过程,它还可以减少错误,所以FastAPI官网介绍优点中就提到这个方案可以将开发人员错误减少高达 40%。对于Python这种动态语言来说,如果不是用mypy强制类型检查,应用Pydantic是非常有必要的。
另外由于集成了Pydantic,所以非常容易在项目中添加ORM(如SQLAlchemy),从请求中获得的对象可以直接传递到数据库,因为已经做过数据验证。反之亦然,可以将从数据库获取的对象直接返回。
相对的,Flask这方面的缺失的。
先提一下WSGI,他的全称是「Python Web Server Gateway Interface」,具体可以看延伸阅读链接三的《PEP 3333》,它是专门为 Web 应用程序和服务器相互交互而编写的 Python 标准。如果你使用过PHP或 Ruby 的人会更容易理解它。Flask的依赖Werkzeug就是WSGI套件,所以Flask支持的是这个老的WSGI,不支持ASGI。
WSGI的问题是无法利用异步达到性能和效率提升,所以Django组织首先提出了ASGI。它的全称是「Asynchronous Server Gateway Interface」,它是一个迭代但基本的重新设计,它提供了异步服务器/应用程序接口,并支持 HTTP、HTTP/2 和 WebSocket。与 WSGI 不同,ASGI 允许每个应用程序有多个异步事件。另外,ASGI 支持同步和异步应用程序。你可以将旧的同步WSGI Web应用程序迁移到 ASGI,也可以使用ASGI构建新的异步 Web 应用程序。
出结论之前,先稍微补充5个名词解释:
uvicorn.workers.UvicornWorker
也可以。都是生产环境推荐的用法。过去一般WSGI的生产环境方案是 Nginx+Gunicorn+Flask(Django)
,而现在ASGI的生产环境方案是 Nginx+Uvicorn+FastAPI
。
再补充一点。FastAPI无论看项目名字还是介绍都能感觉出来它是用于构建API服务的,事实上FastAPI自己的核心代码也确实是这样的,可以说它不是一个传统的、完全自己实现的框架,它更像是一个集各家之长的框架,从一个空壳开始,把需要的、适合的组件组装起来。例如它没有模版引擎,如果你确实需要用它实现一个web应用要渲染模版,你可以再组合你想要的选择,当然还可以用Starlette内置的Jinja2(是的,也是Flask内置的)。
上面提的是FastAPI的优势,但是也不能说明Flask已死,我为什么会这么觉得呢? 主要还是看开发者和用户的人气。
这个「人气」是一个很主观的感受,我能想到的有如下指标:
以上种种在我这里其实都说明Flask已死,大家应该考虑替代品。
哎,有一点伤感,感谢Flask带我入了Web开发的坑。
是的,我认为现在是抛弃Flask的时候了,如果你是一个Python Web服务的初学者请直接使用FastAPI,如果你是一个有一定工作经验的人,我建议下一个项目请使用FastAPI甚至替代现在的项目,欢迎讨论~
写了一篇补充: 理性参与讨论《Flask 已死,FastAPI 永生》