我使用中间件打印HTTP请求体,以避免在每个函数中出现print
语句。但是,在运行客户端代码时,fastapi没有响应。
服务器简化为以下代码:
import typing
import uvicorn
from fastapi import FastAPI
from fastapi import Request, Body
app = FastAPI()
@app.middleware('http')
async def debug_request(request: Request, call_next):
_body = await request.body()
print(_body)
#
response = await call_next(request)
return response
@app.put("/")
def _(
_body: typing.Dict
):
# print(_body) # this statement is replaced by the middleware
return {"detail": "ok"}
if __name__ == '__main__':
uvicorn.run(app, host='localhost', port=8000)
客户端代码如下:
import requests
_url = 'http://localhost:8000/'
_json = {
'row_id': '1'
}
resp = requests.put(_url, json=_json)
if not resp.ok:
print('http-code: ', resp.status_code)
print('http-response: ', resp.text)
我还没有解决方案,但我已经花了相当多的时间来解决这个悬而未决的问题(对于我组织中具有多个自定义MDW的关键应用程序(。这种挂起主要是因为基于@app.middleware("http")
的中间件,是在后台继承Starlette的BaseHTTPMiddleware
创建的。因此,显式继承BaseHTTPMiddleware
编写的MDW也存在这个问题。造成这种情况的原因非常复杂,这就是我迄今为止所理解的:
- 从这里(GitHub Starlette问题(和这里(GitHub FastAPI问题(:我了解到这个方法使用
StreamingResponse
,它有一些问题 - 从这里(GitHub Starlette问题(:我了解到挂起的原因之一是:在API中,请求生命周期中只允许等待
request.json()
一次,而BaseHTTPMiddleware
也会自己创建一个请求对象(这会导致挂起问题,因为这是另一个请求(
最后一个链接还提到,同样导致挂起问题的是,由于StreamingResponse
;响应的读取在第一次读取时不知何故会耗尽,当它进入第二次读取时,它会无限期地等待它,从而导致挂起。(这里的第一个和第二个意思是:在ASGI应用程序中,消息被发送到具有各种类型的客户端和应用程序,如http.response.start
、http.response.body
等(