文章目录
高级用法
客户实例
使用Client实例发出请求将为您提供HTTP连接池,将提供cookie持久性,并允许您在所有传出请求中应用配置。
暗示
Client实例等效于中的Session实例requests
。
注意
从开始httpx==0.10.0
,默认和推荐的Client类是AsyncClient
。重新引入同步支持后,这应该有助于防止破坏更改。
Client
保留与httpx==0.9.*
发行版兼容的同义词,但建议您AsyncClient
尽快迁移到。
用法
建议使用 Client
作为上下文管理器。这将确保在离开with
模块时正确清理连接:
1 2 3 4 5 6 |
>>> with httpx.Client() as client: ... r = client.get('https://example.com') ... >>> r <Response [200 OK]> |
另外,您可以使用以下命令明确关闭连接池而不会阻塞使用.close()
:
1 2 3 4 5 6 7 8 9 |
>>> client = httpx.Client() >>> try: ... r = client.get('https://example.com') ... finally: ... client.close() ... >>> r <Response [200 OK]> |
有了以后Client
,就可以使用快速入门指南中记录的所有功能。
配置
客户端允许您通过将参数传递给Client
构造函数来将配置应用于所有传出请求。
例如,要对每个请求应用一组自定义标头:
1 2 3 4 5 6 7 8 |
>>> url = 'http://httpbin.org/headers' >>> headers = {'user-agent': 'my-app/0.0.1'} >>> with httpx.Client(headers=headers) as client: ... r = client.get(url) ... >>> r.json()['headers']['User-Agent'] 'my-app/0.0.1' |
注意
当您在客户端和请求级别都提供参数时,可能会发生以下两种情况之一:
- 对于 headers,query parameters 和 cookies,这些值将合并为一个。
- 对于所有其他参数,将使用请求级别的值。
此外,Client
接受一些在请求级别不可用的参数。
一个特别有用的参数是 base_url
,它允许您定义一个基本URL,以在所有外发请求之前:
1 2 3 4 5 6 |
>>> with httpx.Client(base_url='http://httpbin.org') as client: ... r = client.get('/headers') ... >>> r.request.url URL('http://httpbin.org/headers') |
有关所有可用客户端级别参数的列表,请参阅Client
API参考。
调用Python Web Apps
您可以配置httpx
客户端以使用 WSGI 协议直接调用Python Web应用程序。
这对于两个主要用例特别有用:
- 使用
httpx
的测试案例中的客户端。 - 在测试期间或开发/登台环境中模拟外部服务。
这是针对Flask应用程序进行集成的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from flask import Flask import httpx app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" with httpx.Client(app=app) as client: r = client.get('http://example/') assert r.status_code == 200 assert r.text == "Hello World!" |
对于某些更复杂的情况,您可能需要自定义WSGI调度。这使您可以:
- 检查 500 错误响应,可以通过设置引发异常
raise_app_exceptions=False
。 - 通过设置
script_name
(WSGI)在子路径上安装 WSGI 应用程序。 - 通过设置
remote_addr
(WSGI)将给定的客户端地址用于请求。
例如:
1 2 3 4 5 |
# Instantiate a client that makes WSGI requests with a client IP of "1.2.3.4". dispatch = httpx.WSGIDispatch(app=app, remote_addr="1.2.3.4") with httpx.Client(dispatch=dispatch) as client: ... |
建立request
您可以Client.build_request()
用来构建请求并进行修改,然后再发送请求。
1 2 3 4 5 6 7 8 |
>>> with httpx.Client() as client: ... req = client.build_request("OPTIONS", "https://example.com") ... req.url.full_path = "*" # Build an 'OPTIONS *' request for CORS ... r = client.send(req) ... >>> r <Response [200 OK]> |
支持 .netrc
HTTPX 支持 .netrc 文件。在trust_env=True
某些情况下,如果未定义auth参数,则HTTPX尝试将auth从.netrc文件添加到请求的标头中。
注意
NETRC文件跨客户端的请求进行缓存。如果需要刷新缓存(例如,由于NETRC文件已更改),则应创建一个新客户端或重新启动解释器。
默认trust_env
为true。设置为false:
1 2 |
>>> httpx.get('https://example.org/', trust_env=False) |
如果NETRC
环境为空,则HTTPX尝试使用默认文件。(~/.netrc
,~/_netrc
)
要更改NETRC
环境:
1 2 3 |
>>> import os >>> os.environ["NETRC"] = "my_default_folder/.my_netrc" |
.netrc 文件内容示例:
1 2 3 4 5 6 |
machine netrcexample.org login example-username password example-password ... |
使用Client
实例时,trust_env
应在客户端本身上设置,而不是在请求方法上设置:
1 2 |
client = httpx.Client(trust_env=False) |
为HTTPX 设置代理
HTTPX 支持设置代理,这与请求通过proxies
参数进行设置的方式相同。例如,将所有HTTP流量转发http://127.0.0.1:3080
到http://127.0.0.1:3081
您的proxies
配置并将所有HTTPS流量转发到您的配置如下所示:
1 2 3 4 5 6 7 |
>>> proxies = { ... "http": "http://127.0.0.1:3080", ... "https": "http://127.0.0.1:3081" ... } >>> with httpx.Client(proxies=proxies) as client: ... ... |
代理可以配置特定的主机,可以所有的主机配置一个代理 在确定用于给定请求的代理配置时,将使用相同的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> proxies = { ... "http://example.com": "...", # Host+Scheme ... "all://example.com": "...", # Host ... "http": "...", # Scheme ... "all": "...", # All ... } >>> with httpx.Client(proxies=proxies) as client: ... ... ... >>> proxy = "..." # Shortcut for {'all': '...'} >>> with httpx.Client(proxies=proxy) as client: ... ... |
警告
为确保代理无法读取您的流量,即使proxy_url使用HTTPS,也建议尽可能使用HTTPS和隧道请求。
默认情况下,httpx.Proxy
它将作为http://...
请求的转发代理,并为请求建立CONNECT
TCP隧道https://
。无论代理url
是http
还是,此设置都不会改变https
。
可以将代理配置为具有不同的行为,例如转发或隧穿所有请求:
1 2 3 4 5 6 7 8 |
proxy = httpx.Proxy( url="https://127.0.0.1", mode="TUNNEL_ONLY" # May be "TUNNEL_ONLY" or "FORWARD_ONLY". Defaults to "DEFAULT". ) with httpx.Client(proxies=proxy) as client: # This request will be tunneled instead of forwarded. r = client.get("http://example.com") |
注意
要使用代理,必须在Client
初始化时传递代理信息,而不是在.get(...)
调用或其他请求方法上传递代理信息。
超时配置
HTTPX会默认在所有地方强制执行超时。
默认行为是TimeoutException
在网络不活动5秒后引发a 。
设置和禁用超时
您可以为单个请求设置超时:
1 2 3 4 5 6 7 |
# Using the top-level API: httpx.get('http://example.com/api/v1/example', timeout=10.0) # Using a client instance: with httpx.Client() as client: client.get("http://example.com/api/v1/example", timeout=10.0) |
或为单个请求禁用超时:
1 2 3 4 5 6 7 |
# Using the top-level API: httpx.get('http://example.com/api/v1/example', timeout=None) # Using a client instance: with httpx.Client() as client: client.get("http://example.com/api/v1/example", timeout=None) |
在客户端上设置默认超时
您可以在客户端实例上设置超时,从而导致给定值 timeout
被用作与此客户端发出的请求的默认值:
1 2 3 4 |
client = httpx.Client() # Use a default 5s timeout everywhere. client = httpx.Client(timeout=10.0) # Use a default 10s timeout everywhere. client = httpx.Client(timeout=None) # Disable all timeouts by default. |
微调配置
HTTPX还允许您更精细地指定超时行为。
可能发生四种不同类型的超时。这些是connect, read,write和pool超时。
- 该连接超时指定等待,直到建立所请求的主机的连接的最大时间量。如果HTTPX在此时间段内无法连接,
ConnectTimeout
则会引发异常。 - 的读取超时被接收指定的最大持续时间,以等待数据的一个块(例如,响应主体的块)。如果HTTPX在此时间段内无法接收数据,
ReadTimeout
则会引发异常。 - 的写入超时指定的最大持续时间,以等待数据块要发送(例如,请求主体的块)。如果HTTPX在此时间段内无法发送数据,
WriteTimeout
则会引发异常。 - 该池超时指定的最大持续时间等待获得连接池中的连接。如果HTTPX在此时间段内无法获取连接,
PoolTimeout
则会引发异常。此处的相关配置是连接池中允许的最大连接数,由进行配置pool_limits
。
您可以为这些值中的任何一个配置超时行为...
1 2 3 4 5 6 |
# A client with a 60s timeout for connecting, and a 10s timeout elsewhere. timeout = httpx.Timeout(10.0, connect_timeout=60.0) client = httpx.Client(timeout=timeout) response = client.get('http://example.com/') |
多部分文件编码
如快速入门中所述, 通过传递一个字典,其中将有效载荷的名称作为键,并将元素的元组或类似于文件的对象或字符串作为值,可以实现多部分文件编码。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')} >>> r = httpx.post("https://httpbin.org/post", files=files) >>> print(r.text) { ... "files": { "upload-file": "<... binary content ...>" }, ... } |
更具体地说,如果将元组用作值,则它必须具有2到3个元素:
- 第一个元素是可选文件名,可以将其设置为
None
。 - 第二个元素可以是类似文件的对象,也可以是将以UTF-8自动编码的字符串。
- 可选的第三个元素可用于指定 要上传的文件的 MIME类型。如果未指定,HTTPX将尝试根据文件名猜测MIME类型,未知文件扩展名默认为“ application / octet-stream”。如果文件名明确设置为,
None
则HTTPX将不包含内容类型MIME头字段。
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> files = {'upload-file': (None, 'text content', 'text/plain')} >>> r = httpx.post("https://httpbin.org/post", files=files) >>> print(r.text) { ... "files": {}, "form": { "upload-file": "text-content" }, ... } |
自定义身份验证
在发出请求或实例化客户端时,该auth
参数可用于传递要使用的身份验证方案。该auth
参数可能是以下之一:
username
/ 的二元组,password
用于基本身份验证。httpx.BasicAuth()
或的实例httpx.DigestAuth()
。- 可调用的,接受请求并返回经过身份验证的请求实例。
- 的子类
httpx.Auth
。
这些中涉及最多的是最后一个,它允许您创建涉及一个或多个请求的身份验证流。httpx.Auth
应该实现的子类def auth_flow(request)
,并产生任何需要发出的请求...
1 2 3 4 5 6 7 8 9 |
class MyCustomAuth(httpx.Auth): def __init__(self, token): self.token = token def auth_flow(self, request): # Send the request, with a custom `X-Authentication` header. request.headers['X-Authentication'] = self.token yield request |
如果身份验证流程需要一个以上的请求,则可以发出多个收益,并在每种情况下获取响应...
1 2 3 4 5 6 7 8 9 10 11 12 |
class MyCustomAuth(httpx.Auth): def __init__(self, token): self.token = token def auth_flow(self, request): response = yield request if response.status_code == 401: # If the server issues a 401 response then resend the request, # with a custom `X-Authentication` header. request.headers['X-Authentication'] = self.token yield request |
自定义身份验证类被设计为不执行任何I / O,因此它们可以与同步和异步客户端实例一起使用。如果要实现要求请求主体的身份验证方案,则需要使用requires_request_body
属性在类上进行指示。
然后,您将可以访问方法request.content
内部.auth_flow()
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<br />class MyCustomAuth(httpx.Auth): requires_request_body = True def __init__(self, token): self.token = token def auth_flow(self, request): response = yield request if response.status_code == 401: # If the server issues a 401 response then resend the request, # with a custom `X-Authentication` header. request.headers['X-Authentication'] = self.sign_request(...) yield request def sign_request(self, request): # Create a request signature, based on `request.method`, `request.url`, # `request.headers`, and `request.content`. ... |
SSL证书
通过HTTPS发出请求时,HTTPX需要验证所请求主机的身份。为此,它使用由受信任的证书颁发机构(CA)交付的SSL证书捆绑包(也称为CA捆绑包)。
更改验证默认值
默认情况下,HTTPX使用提供的CA束CERTIFI。在大多数情况下,这是您想要的,即使某些高级情况可能要求您使用一组不同的证书。
如果要使用自定义CA捆绑包,则可以使用verify
参数。
1 2 3 4 |
import httpx r = httpx.get("https://example.org", verify="path/to/client.pem") |
您还可以禁用SSL验证...
1 2 3 4 |
import httpx r = httpx.get("https://example.org", verify=False) |
客户端实例上的SSL配置
如果使用Client()
实例,则在实例化客户端时应传递任何SSL设置。
1 2 |
client = httpx.Client(verify=False) |
该client.get(...)
方法和其他请求方法不支持在每个请求的基础上更改SSL设置。如果在不同情况下需要不同的SSL设置,则应使用一个以上的客户端实例,每个实例均具有不同的设置。然后,每个客户端将在该池中的所有连接上使用具有特定的固定SSL配置的隔离连接池。
向本地服务器发出HTTPS请求
向本地服务器(例如在上运行的开发服务器)发出请求时localhost
,通常将使用未加密的HTTP连接。
如果确实需要建立与本地服务器的HTTPS连接(例如,测试仅HTTPS服务),则需要创建并使用自己的证书。这是一种实现方法:
- 使用trustme-cli生成一对服务器密钥/证书文件和一个客户端证书文件。
- 启动本地服务器时,传递服务器密钥/证书文件。(这取决于您使用的特定Web服务器。例如,Uvicorn提供
--ssl-keyfile
和--ssl-certfile
选项。) - 告诉HTTPX使用存储在中的证书
client.pem
:
1 2 3 4 5 |
>>> import httpx >>> r = httpx.get("https://localhost:8000", verify="/tmp/client.pem") >>> r Response <200 OK> |
