我尝试重用HTTP会话作为aiohttp docs建议
不要为每个请求创建会话。最有可能您需要一个会话 完全执行所有请求的应用程序。
但是我与请求库一起使用的常规模式不起作用:
def __init__(self):
self.session = aiohttp.ClientSession()
async def get_u(self, id):
async with self.session.get('url') as resp:
json_resp = await resp.json()
return json_resp.get('data', {})
然后我尝试
await client.get_u(1)
我遇到错误
RuntimeError: Timeout context manager should be used inside a task
任何使用async_timeout的解决方法都无济于事。
另一种工作方式:
async def get_u(self, id):
async with aiohttp.ClientSession() as session:
with async_timeout.timeout(3):
async with session.get('url') as resp:
json_resp = await resp.json()
return json_resp.get('data', {})
但是似乎每个请求都创建了会话。
所以我的问题是:如何正确重用aiohttp-session?
UPD:最小的工作示例。 Sanic应用程序具有以下视图
import aiohttp
from sanic.views import HTTPMethodView
class Client:
def __init__(self):
self.session = aiohttp.ClientSession()
self.url = 'https://jsonplaceholder.typicode.com/todos/1'
async def get(self):
async with self.session.get(self.url) as resp:
json_resp = await resp.json()
return json_resp
client = Client()
class ExView(HTTPMethodView):
async def get(self, request):
todo = await client.get()
print(todo)
答案 0 :(得分:1)
我有同样的错误。对我来说,解决方案是在异步函数中初始化客户端。 EG:
SearchClient(object)类:
def __init__(self, search_url: str, api_key: str):
self.search_url = search_url
self.api_key = api_key
self.session = None
async def _get(self, url, attempt=1):
if self.session is None:
self.session = aiohttp.ClientSession(raise_for_status=True)
headers = {
'Content-Type': 'application/json',
'api-key': self.api_key
}
logger.info("Running Search: {}".format(url))
try:
with timeout(60):
async with self.session.get(url, headers=headers) as response:
results = await response.json()
return results
答案 1 :(得分:0)
例如,您可以在应用启动时创建ClientSession
(使用on_startup
信号https://docs.aiohttp.org/en/stable/web_advanced.html#signals)。
将其存储到您的应用程序(aiohttp应用程序具有针对此类问题https://aiohttp.readthedocs.io/en/stable/faq.html#id4的dict界面),并在请求中通过request.app['YOU_CLIENT_SESSION']
来访问您的会话。