aiohhttp中的会话重用

Ale*_*lex 8 python async-await aiohttp sanic

我尝试重用 HTTP 会话作为 aiohttp 文档建议

不要为每个请求创建一个会话。很可能您需要为每个应用程序创建一个会话来共同执行所有请求。

但是我与请求库一起使用的通常模式不起作用:

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', {})
Run Code Online (Sandbox Code Playgroud)

然后我尝试

await client.get_u(1)
Run Code Online (Sandbox Code Playgroud)

我有错误

RuntimeError: Timeout context manager should be used inside a task
Run Code Online (Sandbox Code Playgroud)

任何 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', {})
Run Code Online (Sandbox Code Playgroud)

但似乎每个请求都创建会话。
所以我的问题是:如何正确重用 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)
Run Code Online (Sandbox Code Playgroud)

小智 6

我有同样的错误。我的解决方案是在异步函数中初始化客户端。例如:

class 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
Run Code Online (Sandbox Code Playgroud)

  • 我要做的唯一补充是,如果不使用 ClientSession 的上下文管理器,我们需要 [手动关闭会话](https://docs.aiohttp.org/en/stable/client_quickstart.html#make-a-request)使用“await session.close()”现有应用程序。请参阅[如何关闭aiohttp ClientSession](/sf/answers/3662211521/) (2认同)