개요
2025.05.05-[Python] HTTPX - 비동기/동기 http 라이브러리에서 최상위 API(get, post 등)을 사용하는 기본적인 요청 방법을 확인해 보았다. 이번 글에서는 동일한 호스트로의 반복적인 요청이 있을 때 성능 향상을 가질 수 있는 Client라는 개념에 대해서 알아보고자 한다.
Client
HTTPX는 기본적으로 호스트로 요청을 보낼 때 매번 새로운 연결을 설정한다. 하지만 이 방식은 매번 새 연결을 설정해야 하기 때문에 호스트에 대한 요청 수가 증가할수록 비효율적이다.
이러한 비효율성을 개선하기 위해 Client는 HTTP 연결 풀링을 사용해, 동일한 호스트에 여러 요청을 하는 경우 TCP 연결을 재사용하도록 지원한다. 연결을 재사용함으로써 요청 간 지연 시간을 줄이고, CPU 사용량과 네트워크 혼잡을 감소시키는 이득을 얻을 수 있다. requests 라이브러리에 비유하면 Session 객체와 동일한 역할이라고 할 수 있다.
기본 사용법
Client 객체는 컨텍스트 매니저를 활용해 자동으로 연결을 관리하도록 하는 것이 좋다.
with httpx.Client() as client:
...
당연히 절차적인 방식으로 사용해도 괜찮다.
client = httpx.Client()
try:
...
finally:
client.close()
클라이언트 객체는 최상위 API가 제공하는 모든 기능을 제공하고 있다. 즉, 요청을 보낼 때는 클라이언트 객체의 get, post 등의 함수를 사용하면 된다.
import httpx
with httpx.Client() as client:
headers = {'user-agent': 'my-app/0.0.1'}
params = {'key1': 'value1', 'key2': 'value2'}
r = client.get('https://example.com', headers=headers, params=params)
print(r)
요청 간 구성 공유
만약 모든 요청에 동일한 헤더나 파라미터를 제공하고 싶다면 Client 객체에 전달하여 구성할 수 있다.
import httpx
headers = {'user-agent': 'my-app/0.0.1'}
params = {'key1': 'value1', 'key2': 'value2'}
with httpx.Client(headers=headers, params=params) as client:
r = client.get('https://example.com')
print(r.request.headers)
print(r.request.url)
일종의 기본값을 제공하는 것으로 이해하면 될 것 같다.
구성 병합
클라이언트 수준, 그리고 요청 수준 모두에서 구성 옵션이 제공하는 경우에는 두 값이 결합되거나 요청 수준의 값이 우선된다.
- 결합
헤더, 쿼리 매개변수, 쿠키의 경우에는 값이 결합된다.
- 요청 수준 값 우선
다른 구성의 경우에는 요청 수준의 값을 우선한다.
import httpx
import base64
with httpx.Client(auth=('tom', 'mot123')) as client:
r = client.get('https://example.com', auth=('alice', 'ecila123'))
_, _, auth = r.request.headers['Authorization'].partition(' ')
print(base64.b64decode(auth))
클라이언트 수준에서 제공된 tom이 아니라 요청 수준에서 제공된 alice를 사용한 것을 알 수 있다.
기본 URL 제공
추가로 Client 객체는 모든 발신 요청의 기본 URL을 제공할 수 있다.
import httpx
import base64
with httpx.Client(base_url='http://httpbin.org') as client:
r = client.get('/headers')
print(r.request.url)
요청 시 base_url과 요청 시 제공한 url이 결합된 url로 요청을 보낸다.
참고 문서
https://www.python-httpx.org/advanced/clients/