實(shí)戰(zhàn)指南:從 GET 到文件上傳的 HTTP 請(qǐng)求全解析)
1. 從零上手 Request一個(gè)被低估的 HTTP 客戶(hù)端利器做后端開(kāi)發(fā)或者數(shù)據(jù)采集的朋友大概率都繞不開(kāi)一個(gè)場(chǎng)景需要在自己的代碼里主動(dòng)發(fā)起 HTTP 請(qǐng)求去調(diào)用第三方接口、抓取頁(yè)面數(shù)據(jù)、或者做服務(wù)間的聯(lián)調(diào)測(cè)試。很多人第一反應(yīng)是用curl拼命令行或者用標(biāo)準(zhǔn)庫(kù)里的http.client、urllib硬寫(xiě)。我早期也是這么干的直到有一次要對(duì)接一個(gè)帶鑒權(quán)、帶重試、帶超時(shí)控制的接口用標(biāo)準(zhǔn)庫(kù)寫(xiě)了將近兩百行代碼調(diào)試了一下午最后發(fā)現(xiàn)連 Cookie 都沒(méi)處理好。后來(lái)同事甩給我一個(gè)庫(kù)說(shuō)“你用這個(gè)試試”我花了十分鐘改完代碼量直接砍到二十行。那個(gè)庫(kù)就是Requests。Requests 是 Python 生態(tài)里最流行的 HTTP 客戶(hù)端庫(kù)之一它的設(shè)計(jì)哲學(xué)就一句話讓 HTTP 請(qǐng)求變得像喝水一樣簡(jiǎn)單。你不需要手動(dòng)處理連接池、編碼轉(zhuǎn)換、重定向、Cookie 持久化這些瑣碎的事情它全部幫你封裝好了。不管你是要做接口自動(dòng)化測(cè)試、寫(xiě)爬蟲(chóng)、對(duì)接第三方支付回調(diào)、還是做微服務(wù)之間的健康檢查Requests 都能覆蓋。這篇文章我會(huì)從實(shí)際使用的角度出發(fā)把 Requests 的核心用法、參數(shù)細(xì)節(jié)、踩坑經(jīng)驗(yàn)一次性講透適合剛接觸網(wǎng)絡(luò)編程的新手也適合用了一段時(shí)間但沒(méi)系統(tǒng)梳理過(guò)的老手。2. 為什么我最終選了 Requests 而不是其他方案2.1 標(biāo)準(zhǔn)庫(kù)的痛點(diǎn)和 Requests 的降維打擊Python 標(biāo)準(zhǔn)庫(kù)里其實(shí)自帶了好幾個(gè)能發(fā) HTTP 請(qǐng)求的模塊urllib.request、http.client、urllib3都算。但它們有一個(gè)共同的問(wèn)題API 設(shè)計(jì)太底層了。舉個(gè)例子你只是想發(fā)一個(gè)帶 JSON 體的 POST 請(qǐng)求用urllib.request大概要這么寫(xiě)import urllib.request import json data json.dumps({name: test, value: 123}).encode(utf-8) req urllib.request.Request( https://httpbin.org/post, datadata, headers{Content-Type: application/json}, methodPOST ) with urllib.request.urlopen(req, timeout10) as resp: body resp.read().decode(utf-8) print(json.loads(body))而用 Requests同樣的功能import requests resp requests.post( https://httpbin.org/post, json{name: test, value: 123}, timeout10 ) print(resp.json())代碼量差了將近三倍而且 Requests 的寫(xiě)法一眼就能看懂在干什么。標(biāo)準(zhǔn)庫(kù)那版你得知道data要手動(dòng)編碼、Content-Type要手動(dòng)設(shè)、響應(yīng)要手動(dòng)解碼任何一個(gè)環(huán)節(jié)漏了都會(huì)出問(wèn)題。Requests 把這些全部自動(dòng)化了傳json參數(shù)它自動(dòng)序列化并設(shè)置請(qǐng)求頭調(diào)resp.json()它自動(dòng)反序列化。2.2 和其他第三方庫(kù)的橫向?qū)Ρ犬?dāng)然Python 的 HTTP 客戶(hù)端不止 Requests 一個(gè)。httpx支持異步、aiohttp專(zhuān)攻異步、urllib3是 Requests 的底層依賴(lài)。我實(shí)際項(xiàng)目里這幾個(gè)都用過(guò)說(shuō)說(shuō)我的選型邏輯庫(kù)名同步支持異步支持上手難度適用場(chǎng)景Requests優(yōu)秀不支持極低常規(guī)接口調(diào)用、腳本、測(cè)試httpx優(yōu)秀優(yōu)秀低需要異步且想保留 Requests 風(fēng)格aiohttp不支持優(yōu)秀中等高并發(fā)爬蟲(chóng)、異步服務(wù)urllib3良好不支持中等需要精細(xì)控制連接池如果你的場(chǎng)景是同步調(diào)用為主、并發(fā)量不大、追求開(kāi)發(fā)效率Requests 就是最優(yōu)解。它的文檔質(zhì)量、社區(qū)生態(tài)、Stack Overflow 上的問(wèn)答數(shù)量都是碾壓級(jí)別的遇到問(wèn)題基本一搜就有答案。我見(jiàn)過(guò)太多人一上來(lái)就追求異步結(jié)果項(xiàng)目里總共就調(diào)三五個(gè)接口用異步反而把代碼復(fù)雜度拉高了得不償失。提示Requests 本身不支持異步。如果你的項(xiàng)目確實(shí)需要高并發(fā)異步請(qǐng)求建議直接上 httpx它的 API 和 Requests 高度相似遷移成本很低。2.3 安裝與版本選擇安裝沒(méi)什么好說(shuō)的一條命令pip install requests但版本選擇有個(gè)細(xì)節(jié)值得注意。Requests 在 2.32.0 之前的版本依賴(lài)chardet做編碼檢測(cè)之后換成了charset_normalizer。如果你在老項(xiàng)目里遇到編碼識(shí)別不準(zhǔn)的問(wèn)題可以先確認(rèn)一下版本。查看當(dāng)前版本pip show requests我一般建議鎖定一個(gè)較新的穩(wěn)定版本比如2.32.x系列寫(xiě)進(jìn)requirements.txt里避免不同環(huán)境裝出不同版本導(dǎo)致行為不一致。另外Requests 依賴(lài)urllib3、certifi、idna、charset_normalizer這幾個(gè)包pip會(huì)自動(dòng)處理不用手動(dòng)裝。3. 核心 API 逐個(gè)拆解從 GET 到文件上傳3.1 GET 請(qǐng)求與參數(shù)傳遞的正確姿勢(shì)GET 請(qǐng)求是最常用的但參數(shù)怎么傳有講究。很多人習(xí)慣自己拼 URL# 不推薦的寫(xiě)法 url https://httpbin.org/get?name張三age25city北京 resp requests.get(url)這種寫(xiě)法的問(wèn)題在于中文和特殊字符需要手動(dòng) URL 編碼參數(shù)多了容易拼錯(cuò)而且可讀性差。正確的方式是用params參數(shù)params { name: 張三, age: 25, city: 北京 } resp requests.get(https://httpbin.org/get, paramsparams) print(resp.url) # https://httpbin.org/get?name%E5%BC%A0%E4%B8%89age25city%E5%8C%97%E4%BA%ACRequests 會(huì)自動(dòng)幫你做 URL 編碼中文、空格、特殊符號(hào)都不用手動(dòng)處理。如果某個(gè)參數(shù)需要傳多個(gè)值比如tagpythontagjava可以傳列表params {tag: [python, java, go]} resp requests.get(https://httpbin.org/get, paramsparams)這樣會(huì)生成tagpythontagjavataggo。這個(gè)細(xì)節(jié)很多人不知道遇到需要傳數(shù)組的接口時(shí)容易卡住。3.2 POST 請(qǐng)求的四種數(shù)據(jù)格式POST 請(qǐng)求比 GET 復(fù)雜因?yàn)檎?qǐng)求體的格式有好幾種。Requests 針對(duì)不同格式提供了不同的參數(shù)用錯(cuò)了接口就會(huì)報(bào)錯(cuò)。第一種表單提交application/x-www-form-urlencoded這是最傳統(tǒng)的表單格式用data參數(shù)傳字典resp requests.post( https://httpbin.org/post, data{username: admin, password: 123456} )Requests 會(huì)自動(dòng)把Content-Type設(shè)成application/x-www-form-urlencoded并把字典編碼成usernameadminpassword123456。第二種JSON 提交application/json現(xiàn)在 RESTful 接口基本都用 JSON用json參數(shù)resp requests.post( https://httpbin.org/post, json{username: admin, password: 123456} )注意這里傳的是json而不是data。如果你把字典傳給dataRequests 會(huì)當(dāng)成表單處理服務(wù)端收到的Content-Type就不對(duì)接口大概率返回 400。這個(gè)坑我踩過(guò)不止一次尤其是對(duì)接一些文檔寫(xiě)得不清楚的接口時(shí)一定要先確認(rèn)對(duì)方要的是表單還是 JSON。第三種原始文本text/plain 或其他有些接口要求直接傳一段字符串或者 XML這時(shí)候用data傳字符串resp requests.post( https://httpbin.org/post, dataxmlnametest/name/xml, headers{Content-Type: application/xml} )第四種文件上傳multipart/form-data文件上傳用files參數(shù)files {file: open(report.pdf, rb)} resp requests.post(https://httpbin.org/post, filesfiles)如果要同時(shí)傳文件和表單字段可以這樣files {file: open(report.pdf, rb)} data {description: 月度報(bào)告} resp requests.post(https://httpbin.org/post, filesfiles, datadata)注意用files時(shí)不要手動(dòng)設(shè)置Content-TypeRequests 會(huì)自動(dòng)生成帶boundary的 multipart 頭。手動(dòng)設(shè)置反而會(huì)導(dǎo)致服務(wù)端解析失敗。3.3 響應(yīng)對(duì)象的常用屬性和方法發(fā)完請(qǐng)求拿到resp對(duì)象后怎么讀取結(jié)果也有講究。常用的屬性有這些resp.status_codeHTTP 狀態(tài)碼比如 200、404、500resp.headers響應(yīng)頭是個(gè)大小寫(xiě)不敏感的字典resp.text響應(yīng)體解碼后的字符串resp.content響應(yīng)體的原始字節(jié)處理圖片、文件時(shí)用這個(gè)resp.json()把響應(yīng)體解析成 Python 對(duì)象前提是內(nèi)容是合法 JSONresp.encoding當(dāng)前使用的編碼可以手動(dòng)改resp.elapsed從發(fā)請(qǐng)求到收到響應(yīng)的時(shí)間關(guān)于編碼有個(gè)經(jīng)典坑如果服務(wù)端返回的Content-Type里沒(méi)帶charsetRequests 會(huì)默認(rèn)用ISO-8859-1解碼中文就會(huì)變成亂碼。解決辦法是手動(dòng)指定resp.encoding utf-8 print(resp.text)或者直接用resp.content.decode(utf-8)自己解碼。我一般習(xí)慣先看resp.headers.get(Content-Type)確認(rèn)編碼后再?zèng)Q定怎么處理。3.4 超時(shí)設(shè)置不設(shè)超時(shí)等于埋雷這是新手最容易忽略、老手最重視的一個(gè)參數(shù)。Requests 默認(rèn)沒(méi)有超時(shí)也就是說(shuō)如果服務(wù)端不響應(yīng)你的程序會(huì)一直卡在那里。生產(chǎn)環(huán)境里這是致命的。# 設(shè)置總超時(shí) 10 秒 resp requests.get(https://httpbin.org/get, timeout10) # 分別設(shè)置連接超時(shí)和讀取超時(shí) resp requests.get(https://httpbin.org/get, timeout(3.05, 27))元組形式里第一個(gè)值是連接超時(shí)建立 TCP 連接的時(shí)間第二個(gè)值是讀取超時(shí)等待服務(wù)端返回?cái)?shù)據(jù)的時(shí)間。為什么連接超時(shí)我寫(xiě) 3.05 而不是 3這是 Requests 官方文檔里的建議值因?yàn)?DNS 解析本身可能消耗額外時(shí)間留一點(diǎn)余量能避免邊界情況下的誤判。提示超時(shí)時(shí)間設(shè)多少合適內(nèi)網(wǎng)接口一般 3 到 5 秒夠了公網(wǎng)接口建議 10 到 30 秒。如果是文件下載讀取超時(shí)要設(shè)大一些或者干脆不設(shè)讀取超時(shí)但設(shè)連接超時(shí)。4. 進(jìn)階實(shí)戰(zhàn)會(huì)話、重試、代理與鑒權(quán)4.1 Session 會(huì)話保持與連接復(fù)用如果你要連續(xù)調(diào)同一個(gè)域名的多個(gè)接口用requests.get()每次都新建連接效率低而且 Cookie 不會(huì)自動(dòng)保持。這時(shí)候應(yīng)該用Sessionsession requests.Session() session.headers.update({User-Agent: MyApp/1.0}) # 第一次請(qǐng)求服務(wù)端 Set-Cookie session.post(https://httpbin.org/cookies/set, data{sessionid: abc123}) # 第二次請(qǐng)求Cookie 自動(dòng)帶上 resp session.get(https://httpbin.org/cookies) print(resp.json()) # {cookies: {sessionid: abc123}}Session 的好處有三個(gè)Cookie 自動(dòng)持久化、底層 TCP 連接復(fù)用、公共請(qǐng)求頭統(tǒng)一管理。我做過(guò)一個(gè)測(cè)試連續(xù)發(fā) 100 個(gè)請(qǐng)求到同一個(gè)域名用 Session 比不用 Session 快了將近 40%因?yàn)槭∪チ朔磸?fù)建立 TCP 連接和 TLS 握手的時(shí)間。用完記得關(guān)閉session.close()或者用上下文管理器with requests.Session() as session: resp session.get(https://httpbin.org/get)4.2 重試機(jī)制讓請(qǐng)求更健壯網(wǎng)絡(luò)請(qǐng)求失敗是常態(tài)尤其是調(diào)用第三方接口時(shí)。Requests 本身沒(méi)有內(nèi)置重試但可以通過(guò)urllib3的Retry配合HTTPAdapter實(shí)現(xiàn)from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session requests.Session() retry Retry( total3, backoff_factor0.5, status_forcelist[500, 502, 503, 504], allowed_methods[GET, POST] ) adapter HTTPAdapter(max_retriesretry) session.mount(https://, adapter) session.mount(http://, adapter)這段配置的意思是最多重試 3 次每次間隔按 0.5 秒遞增0.5、1、2 秒遇到 500、502、503、504 這些服務(wù)端錯(cuò)誤時(shí)觸發(fā)重試只對(duì) GET 和 POST 方法生效。backoff_factor的遞增邏輯是{backoff_factor} * (2 ** (retry_number - 1))所以第一次重試等 0.5 秒第二次等 1 秒第三次等 2 秒。這個(gè)指數(shù)退避策略能有效避免在服務(wù)端剛出問(wèn)題時(shí)瘋狂重試把它壓垮。注意allowed_methods在舊版本里叫method_whitelist如果你用的是老版本 urllib3參數(shù)名要改一下。另外POST 請(qǐng)求重試要謹(jǐn)慎如果接口不是冪等的重試可能導(dǎo)致重復(fù)下單、重復(fù)扣款等問(wèn)題。4.3 代理配置的三種方式有些場(chǎng)景下需要走代理比如抓取外部數(shù)據(jù)、調(diào)試不同網(wǎng)絡(luò)環(huán)境。Requests 支持三種配置方式# 方式一字典傳參 proxies { http: http://10.10.1.10:3128, https: http://10.10.1.10:1080 } resp requests.get(https://httpbin.org/get, proxiesproxies) # 方式二帶認(rèn)證的代理 proxies { https: http://user:pass10.10.1.10:3128 } # 方式三Session 級(jí)別全局配置 session requests.Session() session.proxies.update(proxies)如果代理是通過(guò)環(huán)境變量配置的Requests 會(huì)自動(dòng)讀取HTTP_PROXY和HTTPS_PROXY。但要注意NO_PROXY環(huán)境變量可以指定哪些地址不走代理格式是逗號(hào)分隔的域名列表。4.4 鑒權(quán)Basic Auth 與 Bearer Token接口鑒權(quán)是繞不開(kāi)的。最簡(jiǎn)單的 HTTP Basic Authfrom requests.auth import HTTPBasicAuth resp requests.get( https://httpbin.org/basic-auth/admin/123456, authHTTPBasicAuth(admin, 123456) ) # 簡(jiǎn)寫(xiě)形式 resp requests.get( https://httpbin.org/basic-auth/admin/123456, auth(admin, 123456) )Bearer Token 更常見(jiàn)直接放請(qǐng)求頭headers {Authorization: Bearer eyJhbGciOiJIUzI1NiIs...} resp requests.get(https://api.example.com/user, headersheaders)如果是 OAuth2 之類(lèi)的復(fù)雜鑒權(quán)通常需要先調(diào) token 接口拿 access_token再帶著 token 調(diào)業(yè)務(wù)接口。我一般會(huì)封裝一個(gè)函數(shù)在 token 過(guò)期時(shí)自動(dòng)刷新def get_with_token(url, token_manager): headers {Authorization: fBearer {token_manager.get_token()}} resp requests.get(url, headersheaders) if resp.status_code 401: token_manager.refresh() headers[Authorization] fBearer {token_manager.get_token()} resp requests.get(url, headersheaders) return resp5. 踩坑實(shí)錄與常見(jiàn)問(wèn)題速查5.1 編碼亂碼問(wèn)題的完整排查鏈路中文亂碼是 Requests 使用中最常見(jiàn)的問(wèn)題沒(méi)有之一。排查思路按這個(gè)順序走第一步看響應(yīng)頭里的 Content-Typeprint(resp.headers.get(Content-Type)) # 比如 text/html; charsetutf-8如果帶了charsetRequests 會(huì)用它解碼一般不會(huì)亂碼。如果沒(méi)帶Requests 會(huì)走默認(rèn)邏輯可能猜錯(cuò)。第二步手動(dòng)指定編碼resp.encoding utf-8 print(resp.text)第三步如果還不對(duì)用 apparent_encodingprint(resp.apparent_encoding) resp.encoding resp.apparent_encodingapparent_encoding是charset_normalizer庫(kù)根據(jù)內(nèi)容猜出來(lái)的編碼準(zhǔn)確率比默認(rèn)邏輯高很多。但它是計(jì)算出來(lái)的每次訪問(wèn)都會(huì)重新分析所以拿到結(jié)果后最好緩存下來(lái)。第四步終極方案直接操作字節(jié)text resp.content.decode(gbk, errorsignore)有些老網(wǎng)站用的是 GBK 或 GB2312 編碼而且響應(yīng)頭里不寫(xiě)這時(shí)候只能靠猜。errorsignore能跳過(guò)無(wú)法解碼的字節(jié)避免直接拋異常。5.2 SSL 證書(shū)驗(yàn)證失敗的幾種情況調(diào)用 HTTPS 接口時(shí)偶爾會(huì)遇到SSLError。原因通常有三種服務(wù)端證書(shū)過(guò)期或自簽名本地 CA 證書(shū)庫(kù)太舊公司網(wǎng)絡(luò)做了中間人攔截臨時(shí)繞過(guò)驗(yàn)證的方法是verifyFalseresp requests.get(https://self-signed.example.com, verifyFalse)但這會(huì)同時(shí)觸發(fā)一個(gè)警告。要關(guān)掉警告import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)注意verifyFalse只建議在測(cè)試環(huán)境用。生產(chǎn)環(huán)境關(guān)閉證書(shū)驗(yàn)證等于把安全性完全放棄了中間人攻擊可以隨意篡改內(nèi)容。正確的做法是把自簽名證書(shū)加到信任鏈里或者用verify/path/to/ca.pem指定 CA 證書(shū)文件。5.3 重定向處理與歷史記錄Requests 默認(rèn)會(huì)自動(dòng)跟隨重定向最多 30 次。有時(shí)候你需要看中間經(jīng)過(guò)了哪些跳轉(zhuǎn)resp requests.get(https://httpbin.org/redirect/3) print(resp.history) # [Response [302], Response [302], Response [302]] print(resp.url) # https://httpbin.org/getresp.history是一個(gè)列表按順序記錄了每次重定向的響應(yīng)。如果不想自動(dòng)跟隨resp requests.get(https://httpbin.org/redirect/3, allow_redirectsFalse) print(resp.status_code) # 302 print(resp.headers[Location]) # 下一跳地址POST 請(qǐng)求遇到 301、302 時(shí)Requests 會(huì)把方法改成 GET這是符合瀏覽器行為的。但有些接口設(shè)計(jì)不規(guī)范期望 POST 重定向后還是 POST這時(shí)候就會(huì)出問(wèn)題。解決辦法是手動(dòng)處理重定向或者用allow_redirectsFalse自己控制。5.4 常見(jiàn)問(wèn)題速查表問(wèn)題現(xiàn)象可能原因解決方法中文亂碼編碼識(shí)別錯(cuò)誤手動(dòng)設(shè)resp.encoding或用apparent_encoding請(qǐng)求卡死未設(shè)超時(shí)加timeout(3.05, 27)400 Bad Request數(shù)據(jù)格式不對(duì)確認(rèn)用json還是data401 Unauthorized鑒權(quán)信息缺失或過(guò)期檢查 token加自動(dòng)刷新邏輯403 Forbidden被識(shí)別為爬蟲(chóng)加User-Agent等請(qǐng)求頭SSLError證書(shū)驗(yàn)證失敗測(cè)試環(huán)境verifyFalse生產(chǎn)環(huán)境配 CA連接被重置代理配置問(wèn)題檢查proxies參數(shù)和環(huán)境變量響應(yīng)內(nèi)容截?cái)嘧x取超時(shí)太短增大讀取超時(shí)或流式讀取5.5 流式下載大文件的正確做法下載大文件時(shí)如果直接用resp.content整個(gè)文件會(huì)先加載到內(nèi)存里幾百兆的文件能把內(nèi)存吃滿。正確做法是流式讀取resp requests.get(https://example.com/bigfile.zip, streamTrue, timeout(3.05, 60)) with open(bigfile.zip, wb) as f: for chunk in resp.iter_content(chunk_size8192): if chunk: f.write(chunk)streamTrue讓 Requests 不立即下載響應(yīng)體iter_content按塊讀取chunk_size8192是每次讀 8KB。這個(gè)大小可以根據(jù)網(wǎng)絡(luò)情況調(diào)整內(nèi)網(wǎng)可以設(shè)大一點(diǎn)比如 64KB公網(wǎng)建議 8KB 到 16KB。提示流式請(qǐng)求下resp.text和resp.content會(huì)報(bào)錯(cuò)必須用iter_content或iter_lines。另外記得在with塊結(jié)束后連接才會(huì)釋放或者手動(dòng)調(diào)resp.close()。6. 我個(gè)人的幾條實(shí)戰(zhàn)心得用 Requests 這些年有幾個(gè)習(xí)慣是我踩了坑之后養(yǎng)成的分享出來(lái)供參考。第一永遠(yuǎn)設(shè)超時(shí)。不管是腳本還是服務(wù)只要發(fā)請(qǐng)求就加timeout。我見(jiàn)過(guò)太多因?yàn)闆](méi)設(shè)超時(shí)導(dǎo)致整個(gè)服務(wù)線程池被拖垮的案例。哪怕你設(shè)個(gè) 60 秒也比不設(shè)強(qiáng)。第二生產(chǎn)環(huán)境用 Session 而不是裸調(diào)。Session 的連接復(fù)用和 Cookie 管理能省很多事而且方便統(tǒng)一配置重試、代理、請(qǐng)求頭。我一般會(huì)封裝一個(gè)全局的 Session 實(shí)例在應(yīng)用啟動(dòng)時(shí)初始化好。第三日志要打全。出問(wèn)題時(shí)請(qǐng)求的 URL、方法、請(qǐng)求頭、請(qǐng)求體、響應(yīng)狀態(tài)碼、響應(yīng)體前 500 個(gè)字符這些信息能幫你快速定位。我習(xí)慣在封裝層里加一個(gè)開(kāi)關(guān)調(diào)試時(shí)打開(kāi)生產(chǎn)環(huán)境關(guān)掉避免日志爆炸。第四敏感信息不要硬編碼。token、密碼、代理認(rèn)證信息這些走環(huán)境變量或配置中心別直接寫(xiě)在代碼里。我見(jiàn)過(guò)有人把生產(chǎn)環(huán)境的 token 提交到公開(kāi)倉(cāng)庫(kù)結(jié)果被掃出來(lái)盜用損失不小。第五注意請(qǐng)求頻率。調(diào)第三方接口時(shí)看清楚對(duì)方的限流策略。該加 sleep 就加 sleep該用隊(duì)列就用隊(duì)列。把對(duì)方接口打掛了最后倒霉的還是自己。最后再分享一個(gè)小技巧如果你需要快速驗(yàn)證一個(gè)接口能不能通不用寫(xiě)代碼直接在命令行里用python -m requests是不行的但可以用curl先試。不過(guò) Requests 有個(gè)隱藏玩法在 Python 交互式環(huán)境里import requests r requests.get(https://httpbin.org/get) r.status_code r.json()這種即時(shí)反饋的方式比寫(xiě)完整腳本再跑要快得多調(diào)試接口時(shí)特別順手。