FastApi相关总结

语言: CN / TW / HK

highlight: atom-one-dark theme: nico


一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情

FastApi相关总结

先说说感想

上一篇写到了迁移FlaskFastApi的注意事项,其实直到现在我都还不算真正使用过FastApi,也许我也没有资格写这种评价类的文章。不过我还是想说点感想:

  • FastApi的一些资料还不是很成熟,不如Flask和Django的资料那么多。

    所以,不建议没有Flask或者Django或者其他web框架使用经验的用户第一时间上手FastApi。因为遇到问题会比较难解决,能查到的资料相对有限。

    但有问题可以试试去官网搜索,一般都会有解决方案。

  • FastApi属于比较限制的框架,在某些地方控制得比较死,比如接口参数那里。下面我会说到。

也有烦恼

其实我今天抽空在研究@permission装饰器的替代方案,之前是通过修改接口的参数,通过装饰器注入参数到kwargs的方式,获取到用户信息。

但是现在有个问题是,FastApi严格控制了你的接口参数,如果改变接口的参数,FastApi内部会直接跑出参数错误的异常。这就很让人苦恼,于是我开始研究其他的方式:

  • 实现login_required并不一定需要装饰器

    业内实现判断用户是否登录的方法,包括FastApi推荐的也都是: 用中间件结合Request上下文来实现的。一直以来都是我野路子了,具体的做法我这里就不详说了,大概意思是一个HTTP请求分为很多个阶段。

    画个草图:

在这些过程中,会遇到很多个Context,比如咱们的登录状态就应该放到请求之前去做。如果校验通过,则调用下一个context,失败则直接返回RESPONSE。

用Flask类比的话就是@app.after_request()和@app.before_request(),这个都是我印象中的,我没有深入去使用到。放到FastApi里面就是以middleware的形式。

但是我不考虑这种做法,第一是太局限了,基本上会给诸多接口都加上登录的限制,第二是没有对具体的用户权限进行整合,比如有的接口我希望管理员访问,有的接口希望普通用户就能访问。这种情况下,我还是打算采用别的方法。

  • Depends

其实在之前蓝图模块就有看到过这货,只不过不太清楚他是干嘛的。其实它实现的功能和上面的差不多,也是可以调整接口请求的参数。

Depends会去帮你处理请求参数里的信息,基本上它是这么用的:

这就是,我要的滑板鞋!现在问题就可以拆解为,读取request headers里的token字段,然后判断token是否过期等等。最后转换成用户信息,return出来~期间遇到异常,就返回对应的异常即可。

最终的用法

遇到参数问题

Depends接受的其实是一个函数,说是函数,但是它是根据对象是否实现了__call__方法来判断的,Depends相当于是在请求执行之前调用了Depends里面传递的方法,所以我们编写一个Permission类,实现__call__即可。

  • __init__方法

初始化把role的权限值赋给self.role

  • __call__方法

逻辑和之前的permission类似,先判断token是否为空,这边封装了2个exception,分别是认证失败和权限失败。

异常代码,继承了HTTPException。因为FastApi提供了全局监听Exception的方法,方便你处理自定义的异常,所以这就是我们封装自定义异常的原因。

封装好的异常,通过@pity.exception_handler控制异常具体的输出,当是PermissionExceptionAuthException的时候输出对应的内容。

同步代码阻塞问题

当FastApi遇到同步代码(io阻塞,比如请求其他人的接口,特慢那种),会阻塞整个服务,所以建议大家尽可能地使用异步库比如用aiohttp替换requests等,大家可以做个实验测试一下,使用time.sleep来模拟同步操作即可。接着就是可以多开几个worker,阻塞1个不要紧,还有其他的worker在处理事件。

总结

来个首尾呼应吧,其实写到这里,我自己都一脸懵逼。这也就是我发现FastApi的一大问题,并不是它有问题,而是我有问题!有的东西我并不会用,没有的东西,还得自己写!所以也就对应了我之前说,为什么不建议大家没有基础的去挑战这个框架,这个框架它是20级的boss,新手村出来的伙计还是先别打了!

后续虽还是继续使用这个框架,但对于他独特的地方我就不深入去研究了,虽然自己写插件这种形式很能锻炼人,但是那自己写插件我要你这个框架干啥呢?所以合适的地方用合适的武器,不能大炮打蚊子,也不能杀鸡用牛刀。