python 无法使用 HTTP 请求从异步函数中获取 return 值
python Unable to get return values from async function using HTTP requests
我正在尝试将我的 Flask 应用程序重写为使用 uvloop
作为基础的 FastAPI。
当我在没有路由的情况下执行代码时,我没有发现任何问题并按预期执行。但是在我添加路由并使用 Postman 发出请求后抛出错误。
> INFO: ('172.17.0.1', 42352) - "GET /api/v1/getpass HTTP/1.1" 500
> ERROR: Exception in ASGI application Traceback (most recent call
> last): File
> "/usr/local/lib/python3.6/site-packages/uvicorn/protocols/http/httptools_impl.py",
> line 375, in run_asgi
> result = await app(self.scope, self.receive, self.send) File "/usr/local/lib/python3.6/site-packages/starlette/applications.py",
> line 133, in __call__
> await self.error_middleware(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/middleware/errors.py",
> line 177, in __call__
> raise exc from None File "/usr/local/lib/python3.6/site-packages/starlette/middleware/errors.py",
> line 155, in __call__
> await self.app(scope, receive, _send) File "/usr/local/lib/python3.6/site-packages/starlette/exceptions.py", line
> 73, in __call__
> raise exc from None File "/usr/local/lib/python3.6/site-packages/starlette/exceptions.py", line
> 62, in __call__
> await self.app(scope, receive, sender) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 590, in __call__
> await route(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 208, in __call__
> await self.app(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 41, in app
> response = await func(request) File "/usr/local/lib/python3.6/site-packages/fastapi/routing.py", line 111,
> in app
> raw_response = await dependant.call(**values) File "./iowait.py", line 51, in get_pvt
> print(kpair) UnboundLocalError: local variable 'kpair' referenced before assignment
我的代码:
import random
import asyncio as aio
from fastapi import FastAPI
from pydantic import BaseModel
get_id = '/api/v1/getid'
get_pass = '/api/v1/getpass'
app = FastAPI()
key_pass_list = [
{
'uid' : 'uid1',
'pass' : 'pass1'
},
{
'uid' : 'uid2',
'pass' : 'pass2'
},
{
'uid' : 'uid3',
'pass' : 'pass3'
},
]
id_list = [_['uid'] for _ in key_pass_list]
class KeyDoc(BaseModel):
uid : str
async def key_pass(uid):
for keypair in key_pass_list:
if keypair['uid'] == uid:
return keypair
return {uid: 'Key not Found'}
@app.get(get_pass)
async def get_pvt(key_doc: KeyDoc):
uid = key_doc.uid
print('uid :' + uid)
try:
myloop = aio.get_event_loop()
kpair = myloop.run_until_complete(aio.wait([key_pass(uid)]))
await kpair
except Exception as err:
print(err)
print(kpair)
return None
@app.get(get_id)
async def get_pub():
return random.choice(id_list)
@app.get("/")
async def root():
return {"message": "Test-AIO"}
注意
get_id
和 /
路由随时可用,因为没有逻辑,它因 get_pass
请求而失败。
非常感谢对此的任何帮助或指示。
谢谢
这里有两件事。首先,使用 aio.get_event_loop()
会在 await kpair
之前抛出异常 This event loop is already running
,这会抛出您在尝试打印不存在的变量时看到的 UnboundLocalError
。您可以通过在 get_pvt
中的第一个打印语句下添加 kpair = None
来查看此行为。以下是您将如何使用 asyncio.wait
.
构建此结构
@app.get(get_pass)
async def get_pvt(key_doc: KeyDoc):
uid = key_doc.uid
print('uid :' + uid)
done = set()
try:
done, pending = await aio.wait([key_pass(uid)])
except Exception as err:
print(err)
if done:
for task in done:
print(task.result())
return None
我正在尝试将我的 Flask 应用程序重写为使用 uvloop
作为基础的 FastAPI。
当我在没有路由的情况下执行代码时,我没有发现任何问题并按预期执行。但是在我添加路由并使用 Postman 发出请求后抛出错误。
> INFO: ('172.17.0.1', 42352) - "GET /api/v1/getpass HTTP/1.1" 500
> ERROR: Exception in ASGI application Traceback (most recent call
> last): File
> "/usr/local/lib/python3.6/site-packages/uvicorn/protocols/http/httptools_impl.py",
> line 375, in run_asgi
> result = await app(self.scope, self.receive, self.send) File "/usr/local/lib/python3.6/site-packages/starlette/applications.py",
> line 133, in __call__
> await self.error_middleware(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/middleware/errors.py",
> line 177, in __call__
> raise exc from None File "/usr/local/lib/python3.6/site-packages/starlette/middleware/errors.py",
> line 155, in __call__
> await self.app(scope, receive, _send) File "/usr/local/lib/python3.6/site-packages/starlette/exceptions.py", line
> 73, in __call__
> raise exc from None File "/usr/local/lib/python3.6/site-packages/starlette/exceptions.py", line
> 62, in __call__
> await self.app(scope, receive, sender) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 590, in __call__
> await route(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 208, in __call__
> await self.app(scope, receive, send) File "/usr/local/lib/python3.6/site-packages/starlette/routing.py", line
> 41, in app
> response = await func(request) File "/usr/local/lib/python3.6/site-packages/fastapi/routing.py", line 111,
> in app
> raw_response = await dependant.call(**values) File "./iowait.py", line 51, in get_pvt
> print(kpair) UnboundLocalError: local variable 'kpair' referenced before assignment
我的代码:
import random
import asyncio as aio
from fastapi import FastAPI
from pydantic import BaseModel
get_id = '/api/v1/getid'
get_pass = '/api/v1/getpass'
app = FastAPI()
key_pass_list = [
{
'uid' : 'uid1',
'pass' : 'pass1'
},
{
'uid' : 'uid2',
'pass' : 'pass2'
},
{
'uid' : 'uid3',
'pass' : 'pass3'
},
]
id_list = [_['uid'] for _ in key_pass_list]
class KeyDoc(BaseModel):
uid : str
async def key_pass(uid):
for keypair in key_pass_list:
if keypair['uid'] == uid:
return keypair
return {uid: 'Key not Found'}
@app.get(get_pass)
async def get_pvt(key_doc: KeyDoc):
uid = key_doc.uid
print('uid :' + uid)
try:
myloop = aio.get_event_loop()
kpair = myloop.run_until_complete(aio.wait([key_pass(uid)]))
await kpair
except Exception as err:
print(err)
print(kpair)
return None
@app.get(get_id)
async def get_pub():
return random.choice(id_list)
@app.get("/")
async def root():
return {"message": "Test-AIO"}
注意
get_id
和 /
路由随时可用,因为没有逻辑,它因 get_pass
请求而失败。
非常感谢对此的任何帮助或指示。
谢谢
这里有两件事。首先,使用 aio.get_event_loop()
会在 await kpair
之前抛出异常 This event loop is already running
,这会抛出您在尝试打印不存在的变量时看到的 UnboundLocalError
。您可以通过在 get_pvt
中的第一个打印语句下添加 kpair = None
来查看此行为。以下是您将如何使用 asyncio.wait
.
@app.get(get_pass)
async def get_pvt(key_doc: KeyDoc):
uid = key_doc.uid
print('uid :' + uid)
done = set()
try:
done, pending = await aio.wait([key_pass(uid)])
except Exception as err:
print(err)
if done:
for task in done:
print(task.result())
return None