您好,登錄后才能下訂單哦!
這篇文章主要介紹“Python中httptools模塊如何使用”,在日常操作中,相信很多人在Python中httptools模塊如何使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python中httptools模塊如何使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
如果你用過 FastAPI 的話,那么你一定知道 uvicorn,它是一個基于 uvloop 和 httptools 實現的高性能 ASGI 服務器。
其中 uvloop 采用 Cython 編寫,用于替換 asyncio 中的事件循環,可以讓 asyncio 速度增加 2 到 4 倍。而 httptools 是基于 C 語言實現的 HTTP 解析器,用來解析 HTTP 請求的。
httptools 是一個 HTTP 解析器,它首先提供了一個 parse_url 函數,用來解析 URL。
import httptools # 第一個參數必須是 bytes 對象 url = httptools.parse_url( b"http://www.baidu.com" ) # 返回一個 URL 對象 print(url.__class__) """ <class 'httptools.parser.parser.URL'> """
那么這個 URL 對象有哪些屬性呢?
通過源碼可知,總共有七個屬性,我們來測試一下。
import httptools # 第一個參數是 bytes 對象 url = b"http://satori:123456@www.baidu.com:80/s?wd=koishi#flag" url_obj = httptools.parse_url(url) print("協議:", url_obj.schema) print("IP:", url_obj.host) print("端口:", url_obj.port) print("路徑:", url_obj.path) print("查詢參數:", url_obj.query) print("錨點:", url_obj.fragment) print("用戶信息:", url_obj.userinfo) """ 協議: b'http' IP: b'www.baidu.com' 端口: 80 路徑: b'/s' 查詢參數: b'wd=koishi' 錨點: b'flag' 用戶信息: b'satori:123456' """
比較簡單,如果參數不符合 URL 的標準格式,那么會拋出 HttpParserInvalidURLError 錯誤。
然后是 HTTP 請求報文和響應報文的解析,因為報文只是一坨字節流,需要將它解析成某個 Request 對象或 Response 對象,而 httptools 就是干這件事情的。
首先來看一下報文格式,請求報文如下:
接下來是響應報文:
所以無論是請求報文還是響應報文,都由 起始行 + 請求頭/響應頭 + 請求體/響應體 組成。而我們在拿到原始的報文之后,也可以很方便地進行解析,從圖中可以看出最后一個 Header 字段和響應體之間有兩個換行,而換行用 \r\n 表示。因此我們只要按照 "\r\n\r\n" 進行 split 即可,會得到一個數組,數組的第二個元素就是請求體/響應體,第一個元素就是起始行 + 請求頭/響應頭。
然后對數組的第一個元素按照 "\r\n" 再進行 split,又可以得到一個數組,該數組的第一個元素就是起始行,剩余的元素就是請求頭/響應頭。
所以我們在拿到報文之后,完全可以自己手動解析,但 httptools 是用 C 實現的,所以速度會快一些,但干的事情是一樣的。下面來看看 httptools 如何解析請求報文:
from pprint import pprint import httptools # 請求報文 request_payload = b"""POST /index?a=1 HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 26 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Accept: text/html Accept-Encoding: gzip, deflate, sdch Cookie: _octo=GH1.1.1989111283.1493917476; logged_in=yes {"name":"satori","age":17}""" class Request: """ 將請求報文的解析結果封裝成 Request 對象 """ def __init__(self): self.headers = {} self.body = b"" self.path = None def on_url(self, path: bytes): self.path = path def on_header(self, name: bytes, value: bytes): self.headers[name] = value def on_body(self, body: bytes): self.body = body # 實例化 Request 對象 request = Request() # 將 request 作為參數傳到 HttpRequestParser 中 parser = httptools.HttpRequestParser(request) # 傳入請求報文,進行解析 parser.feed_data(request_payload) # 獲取 HTTP 版本 print(parser.get_http_version()) """ 1.1 """ # 是否是長鏈接(Connection 指定為 keep-alive) print(parser.should_keep_alive()) """ True """ # 獲取請求方法 print(parser.get_method()) """ b'POST' """ # 以上幾個都是 HttpRequestParser 對象的方法 # 獲取路徑 print(request.path) """ b'/index?a=1' """ # 獲取請求頭 pprint(request.headers) """ {b'Accept': b'text/html', b'Accept-Encoding': b'gzip, deflate, sdch', b'Cache-Control': b'max-age=0', b'Connection': b'keep-alive', b'Content-Length': b'26', b'Cookie': b'_octo=GH1.1.1989111283.1493917476; logged_in=yes', b'Host': b'localhost:8080', b'Upgrade-Insecure-Requests': b'1'} """ # Cookie 也是請求頭的一部分,但在解析的時候會單獨拿出來 # 再解析成一個字典,然后通過 request.cookies 獲取 # 獲取請求體 print(request.body) """ b'{"name":"satori","age":17}' """
以上就是請求報文的解析,再來看看響應報文。
from pprint import pprint import httptools # 響應報文 response_payload = b"""HTTP/1.1 200 OK Server: TornadoServer/6.1 Content-Type: text/html; charset=UTF-8 Date: Sun, 22 May 2022 17:54:11 GMT Content-Length: 21 name: satori, age: 17""" class Response: """ 將響應報文的解析結果封裝成 Response 對象 """ def __init__(self): self.headers = {} self.body = b"" self.status = b"" def on_header(self, name: bytes, value: bytes): self.headers[name] = value def on_body(self, body: bytes): self.body = body def on_status(self, status: bytes): self.status = status # 實例化 Response 對象 response = Response() # 將 response 作為參數傳到 HttpResponseParser 中 parser = httptools.HttpResponseParser(response) # 傳入響應報文,進行解析 parser.feed_data(response_payload) # 獲取 HTTP 版本 print(parser.get_http_version()) """ 1.1 """ # 是否是長鏈接(不指定 Connection,默認為長連接) print(parser.should_keep_alive()) """ True """ # 獲取狀態碼 print(parser.get_status_code()) """ b'OK' """ # 獲取狀態碼對應的描述 print(response.status) """ b'OK' """ # 獲取響應頭 pprint(response.headers) """ {b'Content-Length': b'21', b'Content-Type': b'text/html; charset=UTF-8', b'Date': b'Sun, 22 May 2022 17:54:11 GMT', b'Server': b'TornadoServer/6.1'} """ # 獲取響應體 print(response.body) """ b'name: satori, age: 17' """
以上就是請求報文和響應報文的解析,但如果你不是手動發送 TCP 請求的話,那么該模塊基本用不到。因為對于任何一個成熟的模塊而言,都具備了報文解析功能。像 requests, httpx, aiohttp 等等,以及一些 web 框架,它們在拿到報文之后會自動解析成某個對象,我們直接通過指定的屬性獲取即可。
而 httptools 便是 uvicorn 的報文解析器,我們在使用 uvicorn 的時候,uvicorn 內部也會自動通過 httptools 將報文解析好,而不需要我們手動解析。
因此這里介紹的 httptools 了解一下即可,我們只需要知道它是基于 C 實現的,性能非常高就行。但我們不會手動使用它,而是在使用某個框架(uvicorn)的時候,由框架自動幫我們將報文解析好。
到此,關于“Python中httptools模塊如何使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。