Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

aiohttp: when is the response.status available?

The Getting Started docs for aiohttp give the following client example:

async with aiohttp.ClientSession() as session:
    async with session.get('https://api.github.com/events') as resp:
        print(resp.status)
        print(await resp.text())

I'm having trouble understanding when the response.status will be available. My understanding is that the coroutines releases control at the await response.read() line. How can I possibly access status before waiting for the response to comeback?

like image 535
robin.keunen Avatar asked Sep 27 '17 10:09

robin.keunen


People also ask

What is client session aiohttp?

Client Session. Client session is the recommended interface for making HTTP requests. Session encapsulates a connection pool (connector instance) and supports keepalives by default.

How does aiohttp work?

Aiohttp is an HTTP server/client for asyncio. It allows users to create asynchronous servers and clients. Also, the aiohttp package works for Client WebSockets and Server WebSockets.

How do I pass headers in aiohttp?

If you need to add HTTP headers to a request, pass them in a dict to the headers parameter. await session. post(url, data='Привет, Мир! ')

What is aiohttp in Python?

Python 3.5 added some new syntax that allows developers to create asynchronous applications and packages easier. One such package is aiohttp which is an HTTP client/server for asyncio. Basically, it allows you to write asynchronous clients and servers.


3 Answers

You first get the HTTP response headers, which include in the first line the status code. If you so choose you can then read the rest of the response body (here with resp.text()). Since the headers are always relatively small and the body may be very large, aiohttp gives you the chance to read both separately.

like image 101
deceze Avatar answered Sep 22 '22 03:09

deceze


Important distinction: await ... may release control of the context, for example if the awaited data is not avalible fast enough. The same goes for the async with ... statement. Therefore your code reaches the line print(resp.status) not until the resp is avalible.

For example the code:

import aiohttp
import asyncio
import urllib.parse
import datetime

async def get(session, url):
    print("[{:%M:%S.%f}] getting {} ...".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname))
    async with session.get(url) as resp:
        print("[{:%M:%S.%f}] {}, status: {}".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname, resp.status))
        doc = await resp.text()
        print("[{:%M:%S.%f}] {}, len: {}".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname, len(doc)))

async def main():
    session = aiohttp.ClientSession()

    url = "http://demo.borland.com/Testsite/stadyn_largepagewithimages.html"
    f1 = asyncio.ensure_future(get(session, url))
    print("[{:%M:%S.%f}] added {} to event loop".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname))

    url = "https://stackoverflow.com/questions/46445019/aiohttp-when-is-the-response-status-available"
    f2 = asyncio.ensure_future(get(session, url))
    print("[{:%M:%S.%f}] added {} to event loop".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname))

    url = "https://api.github.com/events"
    f3 = asyncio.ensure_future(get(session, url))
    print("[{:%M:%S.%f}] added {} to event loop".format(datetime.datetime.now(), urllib.parse.urlsplit(url).hostname))

    await f1
    await f2
    await f3

    session.close()

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

can produce this result:

[16:42.415481] added demo.borland.com to event loop
[16:42.415481] added stackoverflow.com to event loop
[16:42.415481] added api.github.com to event loop
[16:42.415481] getting demo.borland.com ...
[16:42.422481] getting stackoverflow.com ...
[16:42.682496] getting api.github.com ...
[16:43.002515] demo.borland.com, status: 200
[16:43.510544] stackoverflow.com, status: 200
[16:43.759558] stackoverflow.com, len: 110650
[16:43.883565] demo.borland.com, len: 239012
[16:44.089577] api.github.com, status: 200
[16:44.318590] api.github.com, len: 43055

Clarification (thx @deceze): Here you can see (look at the times between the brackets) all coroutines releasing control after sending a request to retrieve the website and a second time while awaiting the text of the response. Also borland, in contrast to stackoverflow, has so much text (other network characteristics excluded) that it's only ready to be displayed after the text from stackoverflow was printed, despite being requested earlier.

like image 21
user3608078 Avatar answered Sep 20 '22 03:09

user3608078


resp object is available inside async with block. Therefore resp.status is available too. Also you can call await on some methods, like resp.text() but is doesn't release control of async with block. You can work with resp even after await has been called.

like image 38
Alex Pshenko Avatar answered Sep 18 '22 03:09

Alex Pshenko