Python實(shí)現(xiàn)HTTP上行請求體的gzip壓縮
前言
先重申核心原理:上行請求體壓縮不是HTTP庫自帶功能,本質(zhì)是你自己把body gzip壓縮,帶上 Content-Encoding: gzip 請求頭,將壓縮二進(jìn)制作為請求體發(fā)送。
所有支持自定義請求body、自定義請求頭的HTTP客戶端都能實(shí)現(xiàn),區(qū)別只是各個庫傳參名稱不一樣:
- requests:
data= - httpx:
content= - aiohttp:
data= - urllib:
data= - pycurl:
POSTFIELDS
下面分「同步庫」「異步庫」給出完整示例,統(tǒng)一復(fù)用gzip壓縮函數(shù)。
通用壓縮工具函數(shù)(所有示例共用)
import gzip
from io import BytesIO
def gzip_compress(raw_bytes: bytes) -> bytes:
buf = BytesIO()
with gzip.GzipFile(fileobj=buf, mode="wb") as f:
f.write(raw_bytes)
return buf.getvalue()
一、標(biāo)準(zhǔn)庫:urllib(無需額外安裝,內(nèi)置)
無需安裝第三方包,適合環(huán)境受限不能裝requests的場景
import json
from urllib import request
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
req = request.Request(url, data=compressed_body, headers=headers, method="POST")
with request.urlopen(req) as resp:
print(resp.read().decode("utf-8"))
缺點(diǎn):API簡陋,不支持連接池、超時易用性差,生產(chǎn)一般不首選。
二、httpx(同步 + 異步,當(dāng)前主流推薦)
新一代HTTP客戶端,兼容requests風(fēng)格,支持http1.1/http2
import httpx
import json
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
# 同步
with httpx.Client(timeout=10) as client:
res = client.post(url, headers=headers, content=compressed_body)
print(res.text)
# 異步版本
"""
import asyncio
async def run():
async with httpx.AsyncClient(timeout=10) as client:
res = await client.post(url, headers=headers, content=compressed_body)
print(res.text)
asyncio.run(run())
"""
httpx 傳二進(jìn)制body參數(shù)名是 content,不是data!
三、aiohttp(異步首選,高并發(fā)場景)
異步生態(tài)標(biāo)準(zhǔn)HTTP客戶端,爬蟲、異步微服務(wù)大量使用
import aiohttp
import asyncio
import json
async def main():
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
headers = {
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
async with aiohttp.ClientSession() as session:
async with session.post(url, data=compressed_body, headers=headers) as resp:
print(await resp.text())
asyncio.run(main())
四、pycurl(底層封裝libcurl,高性能)
基于C庫libcurl,吞吐性能極強(qiáng),適合超高并發(fā)場景;缺點(diǎn):Windows安裝麻煩、API晦澀
import pycurl
import json
from io import BytesIO
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
resp_buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.POST, 1)
c.setopt(c.POSTFIELDS, compressed_body)
c.setopt(c.WRITEDATA, resp_buffer)
headers = [
"Content-Type: application/json; charset=utf-8",
"Content-Encoding: gzip"
]
c.setopt(c.HTTPHEADER, headers)
c.perform()
c.close()
print(resp_buffer.getvalue().decode())
五、tornado.httpclient(Tornado框架內(nèi)置異步客戶端)
如果你項(xiàng)目本身使用Tornado Web框架,可以直接使用內(nèi)置客戶端,無需額外依賴
import json
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
import tornado.ioloop
async def fetch():
url = "http://127.0.0.1:8000/api/upload"
payload = {"data": list(range(2000))}
raw = json.dumps(payload).encode("utf-8")
compressed_body = gzip_compress(raw)
req = HTTPRequest(
url,
method="POST",
body=compressed_body,
headers={
"Content-Type": "application/json; charset=utf-8",
"Content-Encoding": "gzip"
}
)
client = AsyncHTTPClient()
res = await client.fetch(req)
print(res.body.decode())
tornado.ioloop.IOLoop.current().run_sync(fetch)
關(guān)鍵共性注意事項(xiàng)(所有庫通用)
不要使用框架自帶json參數(shù):例如 httpx.post(json={})、requests.post(json={}),這類接口會自動編碼,無法替換成壓縮二進(jìn)制,必須手動序列化+使用原始body參數(shù)。
下行壓縮 ≠ 上行壓縮:
Accept-Encoding只是告訴服務(wù)端:我能接收壓縮響應(yīng);Content-Encoding: gzip才代表:本次請求body已經(jīng)壓縮。
服務(wù)端必須手動解壓:絕大多數(shù)Web框架默認(rèn)不會自動解壓帶有Content-Encoding的請求體,缺少解壓代碼會直接收到亂碼二進(jìn)制。
庫選型建議
- 新項(xiàng)目、同步+異步都需要 → httpx
- 純異步高并發(fā)服務(wù)/爬蟲 → aiohttp
- 不能安裝第三方包、極簡環(huán)境 → urllib(標(biāo)準(zhǔn)庫)
- 極致性能、熟悉libcurl → pycurl
- 老舊項(xiàng)目維持現(xiàn)狀 → requests
到此這篇關(guān)于Python實(shí)現(xiàn)HTTP上行請求體的gzip壓縮的文章就介紹到這了,更多相關(guān)Python HTTP請求體壓縮內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用正則表達(dá)式獲取網(wǎng)頁中所需要的信息
這篇文章主要介紹了Python使用正則獲取網(wǎng)頁中所需要的信息的相關(guān)資料,需要的朋友可以參考下2018-01-01
python安裝virtualenv虛擬環(huán)境步驟圖文詳解
這篇文章主要介紹了python安裝virtualenv虛擬環(huán)境步驟,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
Python數(shù)據(jù)庫sqlite3圖文實(shí)例詳解
SQLite是一個進(jìn)程內(nèi)的庫,實(shí)現(xiàn)了自給自足的、無服務(wù)器的、零配置的、事務(wù)性的SQL數(shù)據(jù)庫引擎,下面這篇文章主要給大家介紹了關(guān)于Python數(shù)據(jù)庫sqlite3的相關(guān)資料,需要的朋友可以參考下2022-09-09
pyqt5 實(shí)現(xiàn)多窗口跳轉(zhuǎn)的方法
今天小編就為大家分享一篇pyqt5 實(shí)現(xiàn)多窗口跳轉(zhuǎn)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06
Python實(shí)現(xiàn)PS圖像明亮度調(diào)整效果示例
這篇文章主要介紹了Python實(shí)現(xiàn)PS圖像明亮度調(diào)整效果,結(jié)合實(shí)例形式分析了Python基于skimage模塊調(diào)整圖片明亮度的原理與具體操作技巧,需要的朋友可以參考下2018-01-01

