深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!

🔸 第一部分:httpx请求入口

我们从最常用的入口开始,看看如何使用httpx库发送HTTP请求。通常,我们会使用 httpx.get()httpx.post() 方法:

import httpx

response = httpx.get('https://example.com')
print(response.status_code)
print(response.text)

🔹 这些方法的背后到底发生了什么呢?我们从httpx.get()方法的实现看起。


🔸 第二部分:get方法的实现

httpx.get() 只是对 httpx.request() 方法的简单封装:

# httpx/_api.py
def get(url: str, *, params: dict = None, headers: dict = None, cookies: dict = None, auth = None, timeout = None, allow_redirects: bool = True, **kwargs):
    return request("GET", url, params=params, headers=headers, cookies=cookies, auth=auth, timeout=timeout, allow_redirects=allow_redirects, **kwargs)

🔹 get()方法将请求方法设置为"GET",然后调用内部的 request() 方法。让我们深入 request() 方法。


🔸 第三部分:request方法揭秘

request() 方法是 httpx 库的核心方法,负责处理所有类型的HTTP请求:

# httpx/_api.py
def request(
    method: str,
    url: str,
    *,
    params: dict = None,
    data: dict = None,
    json: dict = None,
    headers: dict = None,
    cookies: dict = None,
    files: dict = None,
    auth = None,
    timeout = None,
    allow_redirects: bool = True,
    **kwargs
):
    with Client() as client:
        return client.request(
            method, url, params=params, data=data, json=json, headers=headers, cookies=cookies, files=files, auth=auth, timeout=timeout, allow_redirects=allow_redirects, **kwargs
        )

🔹 request() 方法创建一个 Client 对象,并调用 client.request() 来实际发送请求。接下来,我们看看 Client 对象的实现。


🔸 第四部分:Client对象的奥秘

Client 对象在httpx库中扮演了重要角色。它不仅可以发送请求,还能管理会话和连接:

# httpx/_client.py
class Client(BaseClient):
    def request(
        self,
        method: str,
        url: str,
        *,
        params: dict = None,
        data: dict = None,
        json: dict = None,
        headers: dict = None,
        cookies: dict = None,
        files: dict = None,
        auth = None,
        timeout = None,
        allow_redirects: bool = True,
        **kwargs
    ):
        request = self.build_request(
            method, url, params=params, data=data, json=json, headers=headers, cookies=cookies, files=files, auth=auth
        )
        response = self.send(request, timeout=timeout, allow_redirects=allow_redirects, **kwargs)
        return response

🔹 Client 对象的 request() 方法中首先调用 build_request() 方法来构建 Request 对象。然后调用 send() 方法来发送请求。


🔸 第五部分:Request对象的构建

build_request() 方法负责构建一个 Request 对象:

# httpx/_client.py
class Client(BaseClient):
    def build_request(
        self,
        method: str,
        url: str,
        *,
        params: dict = None,
        data: dict = None,
        json: dict = None,
        headers: dict = None,
        cookies: dict = None,
        files: dict = None,
        auth = None
    ) -> Request:
        request = Request(
            method=method,
            url=url,
            params=params,
            data=data,
            json=json,
            headers=headers,
            cookies=cookies,
            files=files,
            auth=auth,
        )
        return request

🔹 build_request() 方法中,将请求的方法、URL、头信息、数据等封装到 Request 对象中。


🔸 第六部分:发送请求

当请求准备好后,Client 对象的 send() 方法负责实际发送HTTP请求:

# httpx/_client.py
class Client(BaseClient):
    def send(
        self,
        request: Request,
        *,
        stream: bool = False,
        timeout = None,
        allow_redirects: bool = True,
        **kwargs
    ) -> Response:
        response = self._send_handling_redirects(request, timeout=timeout, allow_redirects=allow_redirects, **kwargs)
        return response

🔹 send() 方法会处理重定向和超时等情况,通过调用 _send_handling_redirects() 方法来实际发送请求。


🔸 第七部分:处理重定向

_send_handling_redirects() 方法负责处理请求的重定向逻辑:

# httpx/_client.py
class Client(BaseClient):
    def _send_handling_redirects(
        self,
        request: Request,
        *,
        timeout = None,
        allow_redirects: bool = True,
        **kwargs
    ) -> Response:
        response = self._send_single_request(request, timeout=timeout, **kwargs)
        while response.is_redirect and allow_redirects:
            request = self.build_request("GET", response.headers["location"])
            response = self._send_single_request(request, timeout=timeout, **kwargs)
        return response

🔹 通过检查响应的重定向状态并构建新的请求对象,_send_handling_redirects() 方法确保了所有重定向都能被正确处理。


🔸 第八部分:发送单个请求

_send_single_request() 方法通过底层的transport来实际发送请求:

# httpx/_client.py
class Client(BaseClient):
    def _send_single_request(self, request: Request, timeout = None, **kwargs) -> Response:
        transport = self._transport_for_url(request.url)
        response = transport.handle_request(request, timeout=timeout)
        return response

🔹 _send_single_request() 方法中最重要的一步是调用 transport.handle_request() 方法来实际发送请求。


🔸 总结

🔹 通过以上解析,我们了解了 httpx 库从发送请求到接收响应的全过程。从 httpx.get() 方法开始,经过 Client 对象的处理、Request 的构建、请求的发送和重定向的处理,最终构建 Response 对象。这一系列流程确保了 httpx 库能够简洁、高效地处理HTTP请求,让开发者可以专注于业务逻辑的实现。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_.Switch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值