Introduction

HTTP/2 is an update to the classic HTTP protocol which aims to increase network efficiency without requiring large changes to the existing protocol API. It seeks to maintain a single connection between a client and server, as opposed to HTTP/1.1 where a separate TCP session is created for each TCP request. Furthermore, it seeks to add support for concurrency, which is not available in HTTP/1.1; features like multithreading and load balancing notwithstanding, a server must process each HTTP request sequentially, which is not ideal for network protocols which are typically IO- rather than CPU-bound. To learn more, visit https://http2.github.io/.

We will use the HTTPX library on top of asyncio in order to implement HTTP/2 GET and POST requests in Python. We cannot use the famous requests module, as this only supports HTTP/1.1. HTTPX supports versions 1.1 and 2, as well as synchronous and asynchronous operations. We will use Python’s built-in asyncio library to provide us with an async execution context. For more details about both, please visit https://www.python-httpx.org/ and https://docs.python.org/3/library/asyncio.html.

GET Requests

First, install HTTPX with HTTP/2 support. asyncio should be installed by default with your Python installation.

pip install httpx[http2]

The example code below sends an HTTP/2 GET request to https://caniuse.com and prints the status code. If all goes well, you should receive code 200. If the website you are attempting to connect to does not support HTTP/2, you will receive a 405 “Method Not Allowed” status code.

import httpx
import asyncio

url = "https://caniuse.com"

async def main():
    async with httpx.AsyncClient(http2=True) as client:
        resp = await client.get(url)
        print(resp.status_code)

asyncio.run(main())

Above, we define an async function, and then pass it to the asyncio execution context. Inside the function, we use the httpx.AsyncClient, which is analogous to the session object in requests. The async keyword must be applied to both the function and the “with…as…” internal context.

HTTPX strives to replicate the requests API wherever possible, so lines 8 and 9 should be familiar to developers who have used that module. The only difference is the use of the ‘await’ keyword to denote our actual asynchronous function call.

POST Requests

The below code sends a POST request to https://caniuse.com with a standard username and password payload (there is not an actual login form on the site to receive this payload). It looks and functions very similar to the GET request above; the only difference is the ‘json’ dictionary which is passed as a payload. This corresponds to the ‘data’ dictionary which is used to pass POST parameters in requests. HTTPX automatically sets a ‘Content-Type: application/json’ header.

import httpx
import asyncio

url = "https://caniuse.com"

async def main():
    async with httpx.AsyncClient(http2=True) as client:
        resp = await client.post(url, json={'username': 'whocares', 
                                            'password': 'notloginform'})
        print(resp.status_code)

asyncio.run(main())

Leave a Reply

Your email address will not be published. Required fields are marked *