http.client --- HTTP 協議客戶端

原始碼: Lib/http/client.py


此模組定義了實現 HTTP 和 HTTPS 協議客戶端的類。通常不直接使用它 —— 模組 urllib.request 使用它來處理使用 HTTP 和 HTTPS 的 URL。

參見

對於更高級別的 HTTP 客戶端介面,推薦使用 Requests 包

備註

僅當 Python 編譯時帶有 SSL 支援(透過 ssl 模組)時,HTTPS 支援才可用。

可用性:非 WASI。

此模組在 WebAssembly 上不起作用或不可用。有關更多資訊,請參閱 WebAssembly 平臺

此模組提供了以下類:

class http.client.HTTPConnection(host, port=None, [timeout, ]source_address=None, blocksize=8192)

一個 HTTPConnection 例項表示與一個 HTTP 伺服器的一次事務。它應該透過傳遞主機和可選的埠號來例項化。如果沒有傳遞埠號,則從主機字串中提取埠(如果其形式為 host:port),否則使用預設的 HTTP 埠 (80)。如果給定了可選的 timeout 引數,阻塞操作(如連線嘗試)將在指定的秒數後超時(如果沒有給定,則使用全域性預設超時設定)。可選的 source_address 引數可以是一個 (host, port) 元組,用作發起 HTTP 連線的源地址。可選的 blocksize 引數設定了傳送類檔案訊息體的緩衝區大小(以位元組為單位)。

例如,以下呼叫都會建立連線到同一主機和埠的例項:

>>> h1 = http.client.HTTPConnection('www.python.org')
>>> h2 = http.client.HTTPConnection('www.python.org:80')
>>> h3 = http.client.HTTPConnection('www.python.org', 80)
>>> h4 = http.client.HTTPConnection('www.python.org', 80, timeout=10)

在 3.2 版本發生變更: 添加了 source_address

在 3.4 版本發生變更: strict 引數已被移除。不再支援 HTTP 0.9 風格的“簡單響應”。

在 3.7 版本發生變更: 添加了 blocksize 引數。

class http.client.HTTPSConnection(host, port=None, *, [timeout, ]source_address=None, context=None, blocksize=8192)

HTTPConnection 的一個子類,使用 SSL 與安全伺服器進行通訊。預設埠是 443。如果指定了 context,它必須是一個 ssl.SSLContext 例項,用於描述各種 SSL 選項。

請閱讀 安全考量 以獲取有關最佳實踐的更多資訊。

在 3.2 版本發生變更: 添加了 source_addresscontextcheck_hostname

在 3.2 版本發生變更: 此類現在在可能的情況下支援 HTTPS 虛擬主機(即,如果 ssl.HAS_SNI 為真)。

在 3.4 版本發生變更: strict 引數已被移除。不再支援 HTTP 0.9 風格的“簡單響應”。

在 3.4.3 版本發生變更: 此類現在預設執行所有必要的證書和主機名檢查。要恢復到以前未驗證的行為,可以將 ssl._create_unverified_context() 傳遞給 context 引數。

在 3.8 版本發生變更: 對於預設的 context,或者當使用自定義 context 傳遞 cert_file 時,此類現在會為 ssl.SSLContext.post_handshake_auth 啟用 TLS 1.3。

在 3.10 版本發生變更: 當沒有提供 context 時,此類現在會發送一個帶有協議指示符 http/1.1 的 ALPN 擴充套件。自定義的 context 應使用 set_alpn_protocols() 來設定 ALPN 協議。

在 3.12 版本發生變更: 已移除已棄用的 key_filecert_filecheck_hostname 引數。

class http.client.HTTPResponse(sock, debuglevel=0, method=None, url=None)

連線成功後返回其例項的類。不由使用者直接例項化。

在 3.4 版本發生變更: strict 引數已被移除。不再支援 HTTP 0.9 風格的“簡單響應”。

此模組提供了以下函式:

http.client.parse_headers(fp)

從一個代表 HTTP 請求/響應的檔案指標 fp 中解析標頭。該檔案必須是一個 BufferedIOBase 讀取器(即非文字),並且必須提供一個有效的 RFC 2822 風格的標頭。

此函式返回一個 http.client.HTTPMessage 的例項,該例項包含標頭欄位,但沒有有效負載(與 HTTPResponse.msghttp.server.BaseHTTPRequestHandler.headers 相同)。返回後,檔案指標 fp 已準備好讀取 HTTP 主體。

備註

parse_headers() 不解析 HTTP 訊息的起始行;它只解析 Name: value 格式的行。檔案必須已準備好讀取這些欄位行,因此在呼叫該函式之前,第一行應已被消費。

以下異常會在適當的時候被引發:

exception http.client.HTTPException

此模組中其他異常的基類。它是 Exception 的子類。

exception http.client.NotConnected

HTTPException 的子類。

exception http.client.InvalidURL

HTTPException 的子類,在給定的埠非數字或為空時引發。

exception http.client.UnknownProtocol

HTTPException 的子類。

exception http.client.UnknownTransferEncoding

HTTPException 的子類。

exception http.client.UnimplementedFileMode

HTTPException 的子類。

exception http.client.IncompleteRead

HTTPException 的子類。

exception http.client.ImproperConnectionState

HTTPException 的子類。

exception http.client.CannotSendRequest

ImproperConnectionState 的子類。

exception http.client.CannotSendHeader

ImproperConnectionState 的子類。

exception http.client.ResponseNotReady

ImproperConnectionState 的子類。

exception http.client.BadStatusLine

HTTPException 的子類。如果伺服器響應了我們不理解的 HTTP 狀態碼,則會引發此異常。

exception http.client.LineTooLong

HTTPException 的子類。在從伺服器接收到的 HTTP 協議中出現過長的行時引發。

exception http.client.RemoteDisconnected

ConnectionResetErrorBadStatusLine 的子類。由 HTTPConnection.getresponse() 在嘗試讀取響應時沒有從連線中讀取到任何資料時引發,這表明遠端端已關閉連線。

在 3.5 版本加入: 以前,會引發 BadStatusLine('')

此模組中定義的常量是:

http.client.HTTP_PORT

HTTP 協議的預設埠(總是 80)。

http.client.HTTPS_PORT

HTTPS 協議的預設埠(總是 443)。

http.client.responses

此字典將 HTTP 1.1 狀態碼對映到 W3C 名稱。

示例:http.client.responses[http.client.NOT_FOUND]'Not Found'

請參閱 HTTP 狀態碼 獲取此模組中可作為常量的 HTTP 狀態碼列表。

HTTPConnection 物件

HTTPConnection 例項有以下方法:

HTTPConnection.request(method, url, body=None, headers={}, *, encode_chunked=False)

這將使用 HTTP 請求方法 method 和請求 URI url 向伺服器傳送請求。提供的 url 必須是絕對路徑,以符合 RFC 2616 §5.1.2(除非連線到 HTTP 代理伺服器或使用 OPTIONSCONNECT 方法)。

如果指定了 body,則在標頭完成後傳送指定的資料。它可以是一個 str、一個類位元組物件、一個開啟的檔案物件,或者一個 bytes 的可迭代物件。如果 body 是一個字串,它會以 ISO-8859-1 編碼,這是 HTTP 的預設編碼。如果它是一個類位元組物件,則按原樣傳送位元組。如果它是一個檔案物件,則傳送檔案的內容;此檔案物件應至少支援 read() 方法。如果檔案物件是 io.TextIOBase 的例項,read() 方法返回的資料將以 ISO-8859-1 編碼,否則 read() 返回的資料將按原樣傳送。如果 body 是一個可迭代物件,則可迭代物件的元素將按原樣傳送,直到可迭代物件耗盡。

headers 引數應該是一個與請求一起傳送的額外 HTTP 標頭的對映。必須提供一個 Host 標頭,以符合 RFC 2616 §5.1.2(除非連線到 HTTP 代理伺服器或使用 OPTIONSCONNECT 方法)。

如果 headers 中既不包含 Content-Length 也不包含 Transfer-Encoding,但存在請求體,則會自動新增其中一個標頭欄位。如果 bodyNone,對於需要主體的請求方法(PUTPOSTPATCH),Content-Length 標頭將被設定為 0。如果 body 是一個字串或一個非檔案的類位元組物件,Content-Length 標頭將被設定為其長度。任何其他型別的 body(通常是檔案和可迭代物件)將被分塊編碼,並且會自動設定 Transfer-Encoding 標頭而不是 Content-Length。

encode_chunked 引數僅在 headers 中指定了 Transfer-Encoding 時才相關。如果 encode_chunkedFalse,HTTPConnection 物件假定所有編碼都由呼叫程式碼處理。如果為 True,主體將被分塊編碼。

例如,要向 https://docs.python.club.tw/3/ 傳送一個 GET 請求:

>>> import http.client
>>> host = "docs.python.org"
>>> conn = http.client.HTTPSConnection(host)
>>> conn.request("GET", "/3/", headers={"Host": host})
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
200 OK

備註

分塊傳輸編碼已新增到 HTTP 協議 1.1 版本中。除非已知 HTTP 伺服器能處理 HTTP 1.1,否則呼叫者必須指定 Content-Length,或者必須傳遞一個 str 或一個非檔案的類位元組物件作為主體表示。

在 3.2 版本發生變更: body 現在可以是一個可迭代物件。

在 3.6 版本發生變更: 如果 headers 中既未設定 Content-Length 也未設定 Transfer-Encoding,檔案和可迭代的 body 物件現在會被分塊編碼。添加了 encode_chunked 引數。不會嘗試為檔案物件確定 Content-Length。

HTTPConnection.getresponse()

應在傳送請求後呼叫,以獲取伺服器的響應。返回一個 HTTPResponse 例項。

備註

請注意,您必須在向伺服器傳送新請求之前讀取完整的響應。

在 3.5 版本發生變更: 如果引發了 ConnectionError 或其子類,HTTPConnection 物件將在傳送新請求時準備好重新連線。

HTTPConnection.set_debuglevel(level)

設定除錯級別。預設除錯級別為 0,表示不列印除錯輸出。任何大於 0 的值都會導致所有當前定義的除錯輸出列印到 stdout。debuglevel 會傳遞給任何新建立的 HTTPResponse 物件。

在 3.1 版本加入。

HTTPConnection.set_tunnel(host, port=None, headers=None)

設定用於 HTTP CONNECT 隧道的主機和埠。這允許透過代理伺服器執行連線。

hostport 引數指定隧道連線的端點(即包含在 CONNECT 請求中的地址,而不是代理伺服器的地址)。

headers 引數應該是一個與 CONNECT 請求一起傳送的額外 HTTP 標頭的對映。

根據 RFC 的規定,HTTP CONNECT 隧道請求使用 HTTP/1.1,因此必須提供一個 HTTP Host: 標頭,該標頭必須與作為 CONNECT 請求目標的 authority-form 形式的請求目標相匹配。如果未透過 headers 引數提供 HTTP Host: 標頭,則會自動生成並傳輸一個。

例如,要透過在本地埠 8080 上執行的 HTTPS 代理伺服器進行隧道,我們會將代理的地址傳遞給 HTTPSConnection 建構函式,並將我們最終想要訪問的主機地址傳遞給 set_tunnel() 方法:

>>> import http.client
>>> conn = http.client.HTTPSConnection("localhost", 8080)
>>> conn.set_tunnel("www.python.org")
>>> conn.request("HEAD","/index.html")

在 3.2 版本加入。

在 3.12 版本發生變更: HTTP CONNECT 隧道請求使用 HTTP/1.1 協議,從 HTTP/1.0 協議升級而來。Host: HTTP 標頭對於 HTTP/1.1 是強制性的,因此如果 headers 引數中未提供,將自動生成並傳輸一個。

HTTPConnection.get_proxy_response_headers()

返回一個字典,其中包含從代理伺服器收到的對 CONNECT 請求的響應標頭。

如果未傳送 CONNECT 請求,則此方法返回 None

3.12 新版功能.

HTTPConnection.connect()

連線到建立物件時指定的伺服器。預設情況下,如果客戶端尚未建立連線,則在發出請求時會自動呼叫此方法。

引發一個 審計事件 http.client.connect,附帶引數 self, host, port

HTTPConnection.close()

關閉與伺服器的連線。

HTTPConnection.blocksize

用於傳送類檔案訊息體的緩衝區大小(以位元組為單位)。

在 3.7 版本加入。

作為使用上述 request() 方法的替代方案,您還可以透過使用下面的四個函式來逐步傳送請求。

HTTPConnection.putrequest(method, url, skip_host=False, skip_accept_encoding=False)

這應該是與伺服器建立連線後的第一個呼叫。它向伺服器傳送一行,包括 method 字串、url 字串和 HTTP 版本(HTTP/1.1)。要停用自動傳送 Host:Accept-Encoding: 標頭(例如,為了接受額外的內容編碼),請為 skip_hostskip_accept_encoding 指定非 False 值。

HTTPConnection.putheader(header, argument[, ...])

向伺服器傳送一個 RFC 822 風格的標頭。它向伺服器傳送一行,包括標頭、一個冒號和一個空格,以及第一個引數。如果給出更多引數,則會發送續行,每行由一個製表符和一個引數組成。

HTTPConnection.endheaders(message_body=None, *, encode_chunked=False)

向伺服器傳送一個空行,表示標頭結束。可選的 message_body 引數可用於傳遞與請求相關的訊息體。

如果 encode_chunkedTruemessage_body 的每次迭代結果將按照 RFC 7230 第 3.3.1 節的規定進行分塊編碼。資料的編碼方式取決於 message_body 的型別。如果 message_body 實現了 緩衝區介面,編碼將產生一個單獨的資料塊。如果 message_body 是一個 collections.abc.Iterablemessage_body 的每次迭代將產生一個數據塊。如果 message_body 是一個檔案物件,每次呼叫 .read() 將產生一個數據塊。此方法在 message_body 結束後立即自動發出分塊編碼資料結束的訊號。

備註

由於分塊編碼規範,迭代器主體產生的空塊將被分塊編碼器忽略。這是為了避免由於格式錯誤的編碼而導致目標伺服器提前終止對請求的讀取。

在 3.6 版本發生變更: 添加了分塊編碼支援和 encode_chunked 引數。

HTTPConnection.send(data)

向伺服器傳送資料。這應該僅在呼叫了 endheaders() 方法之後且在呼叫 getresponse() 之前直接使用。

引發一個 審計事件 http.client.send,附帶引數 self, data

HTTPResponse 物件

一個 HTTPResponse 例項包裝了來自伺服器的 HTTP 響應。它提供了對請求標頭和實體主體的訪問。響應是一個可迭代物件,可以在 with 語句中使用。

在 3.5 版本發生變更: 現在實現了 io.BufferedIOBase 介面,並支援其所有的讀取器操作。

HTTPResponse.read([amt])

讀取並返回響應體,或者最多讀取接下來的 amt 個位元組。

HTTPResponse.readinto(b)

將響應體中最多接下來的 len(b) 個位元組讀入緩衝區 b。返回讀取的位元組數。

在 3.3 版本加入。

HTTPResponse.getheader(name, default=None)

返回標頭 name 的值,如果沒有匹配 name 的標頭,則返回 default。如果存在多個同名 name 的標頭,則返回所有值並用 ‘, ’ 連線。如果 default 是除單個字串外的任何可迭代物件,其元素同樣會用逗號連線後返回。

HTTPResponse.getheaders()

返回一個 (header, value) 元組列表。

HTTPResponse.fileno()

返回底層套接字的 fileno

HTTPResponse.msg

一個包含響應標頭的 http.client.HTTPMessage 例項。http.client.HTTPMessageemail.message.Message 的子類。

HTTPResponse.version

伺服器使用的 HTTP 協議版本。HTTP/1.0 為 10,HTTP/1.1 為 11。

HTTPResponse.url

所檢索資源的 URL,通常用於確定是否發生了重定向。

HTTPResponse.headers

響應的標頭,形式為 email.message.EmailMessage 例項。

HTTPResponse.status

伺服器返回的狀態碼。

HTTPResponse.reason

伺服器返回的原因短語。

HTTPResponse.debuglevel

一個除錯鉤子。如果 debuglevel 大於零,在讀取和解析響應時,訊息將被列印到 stdout。

HTTPResponse.closed

如果流已關閉,則為 True

HTTPResponse.geturl()

自 3.9 版本起已棄用: 已棄用,建議使用 url

HTTPResponse.info()

自 3.9 版本起已棄用: 已棄用,建議使用 headers

HTTPResponse.getcode()

自 3.9 版本起已棄用: 已棄用,建議使用 status

示例

以下是使用 GET 方法的示例會話:

>>> import http.client
>>> conn = http.client.HTTPSConnection("www.python.org")
>>> conn.request("GET", "/")
>>> r1 = conn.getresponse()
>>> print(r1.status, r1.reason)
200 OK
>>> data1 = r1.read()  # This will return entire content.
>>> # The following example demonstrates reading data in chunks.
>>> conn.request("GET", "/")
>>> r1 = conn.getresponse()
>>> while chunk := r1.read(200):
...     print(repr(chunk))
b'<!doctype html>\n<!--[if"...
...
>>> # Example of an invalid request
>>> conn = http.client.HTTPSConnection("docs.python.org")
>>> conn.request("GET", "/parrot.spam")
>>> r2 = conn.getresponse()
>>> print(r2.status, r2.reason)
404 Not Found
>>> data2 = r2.read()
>>> conn.close()

以下是使用 HEAD 方法的示例會話。請注意,HEAD 方法從不返回任何資料。

>>> import http.client
>>> conn = http.client.HTTPSConnection("www.python.org")
>>> conn.request("HEAD", "/")
>>> res = conn.getresponse()
>>> print(res.status, res.reason)
200 OK
>>> data = res.read()
>>> print(len(data))
0
>>> data == b''
True

以下是使用 POST 方法的示例會話:

>>> import http.client, urllib.parse
>>> params = urllib.parse.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})
>>> headers = {"Content-type": "application/x-www-form-urlencoded",
...            "Accept": "text/plain"}
>>> conn = http.client.HTTPConnection("bugs.python.org")
>>> conn.request("POST", "", params, headers)
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
302 Found
>>> data = response.read()
>>> data
b'Redirecting to <a href="https://bugs.python.org/issue12524">https://bugs.python.org/issue12524</a>'
>>> conn.close()

客戶端的 HTTP PUT 請求與 POST 請求非常相似。區別僅在於伺服器端,HTTP 伺服器會允許透過 PUT 請求建立資源。需要注意的是,自定義 HTTP 方法也在 urllib.request.Request 中透過設定相應的方法屬性來處理。以下是使用 PUT 方法的示例會話:

>>> # This creates an HTTP request
>>> # with the content of BODY as the enclosed representation
>>> # for the resource https://:8080/file
...
>>> import http.client
>>> BODY = "***filecontents***"
>>> conn = http.client.HTTPConnection("localhost", 8080)
>>> conn.request("PUT", "/file", BODY)
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
200, OK

HTTPMessage 物件

class http.client.HTTPMessage(email.message.Message)

一個 http.client.HTTPMessage 例項持有來自 HTTP 響應的標頭。它是使用 email.message.Message 類實現的。