fastapi 的 middleware 怎么改成同步模式?
我想写一个验证身份的中间件
@app.middleware("http")
async def get_user_id(request: Request, call_next):
from core.mysql.models import SessionTable
from core.mysql.models import SessionTable
from core.mysql.models import UserTable
from apps.user.schemas import User
from playhouse.shortcuts import model_to_dict
session_key = request.cookies.get("session_key")
if session_key:
try:
session: SessionTable | None = SessionTable.get_or_none(
session_key=session_key)
if session:
user_id = session.user_id
if user_id:
request.state.user_id = user_id
user: UserTable | None = UserTable.get_or_none(id=user_id)
request.state.user = User(**model_to_dict(user))
except Exception as error:
logger.warning(error)
if not session_key or not request.state.get('user_id', None):
return Response(status_code=401, content='Invalid token')
response = call_next(request)
return response
但是有一个问题,就是中间件的函数,必须要加 async,这样就变成了一个同步函数了
非常的令人讨厌!
我不喜欢异步,因为我用的 peewee 等库都不支持异步
比如我们需要在 middleware 中使用 pymysql、redis-py 这些同步库的时候,就会有麻烦
怎么让中间件不加 async?
如果我把 def get_user_id
前面的 async
删掉的话,就会报错
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 429, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/fastapi/applications.py", line 276, in __call__
await super().__call__(scope, receive, send)
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
await self.middleware_stack(scope, receive, send)
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
raise exc
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
await self.app(scope, receive, _send)
File "/Users/ponponon/.local/share/virtualenvs/whoisface-dx42pPyK/lib/python3.11/site-packages/starlette/middleware/base.py", line 108, in __call__
response = await self.dispatch_func(request, call_next)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object Response can't be used in 'await' expression
回复
1个回答
test
2024-07-01
from fastapi import FastAPI, Request, Response
from starlette.concurrency import run_in_threadpool
app = FastAPI()
def sync_code():
# 这里放你的同步代码
pass
@app.middleware("http")
async def sync_middleware(request: Request, call_next):
await run_in_threadpool(sync_code)
response = await call_next(request)
return response
你删掉了async,自然就会报错,因为你下面的代码用了await,中间件是要异步的,你试试上面的方法
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容