最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python Requests實(shí)現(xiàn)API請(qǐng)求重試與超時(shí)配置全解析

 更新時(shí)間:2025年11月28日 08:21:22   作者:站大爺IP  
API請(qǐng)求的穩(wěn)定性直接決定系統(tǒng)可靠性,本文通過真實(shí)案例拆解,Python如何用Requests庫實(shí)現(xiàn)防抖動(dòng)+抗異常的健壯請(qǐng)求方案,需要的可以了解下

?在電商物流追蹤、金融數(shù)據(jù)監(jiān)控等場景中,API請(qǐng)求的穩(wěn)定性直接決定系統(tǒng)可靠性。當(dāng)順豐API因網(wǎng)絡(luò)抖動(dòng)返回503錯(cuò)誤,或因跨地域調(diào)用出現(xiàn)10秒延遲時(shí),如何確保程序不崩潰且數(shù)據(jù)不丟失?本文通過真實(shí)案例拆解,用Requests庫實(shí)現(xiàn)"防抖動(dòng)+抗異常"的健壯請(qǐng)求方案。

一、血淚教訓(xùn):那些年踩過的API坑

某跨境電商系統(tǒng)在"黑色星期五"大促期間突發(fā)故障:調(diào)用順豐國際件接口時(shí),30%的請(qǐng)求因超時(shí)失敗,導(dǎo)致2000+包裹狀態(tài)同步延遲。事后分析發(fā)現(xiàn)三大元兇:

  • 固定超時(shí)陷阱:設(shè)置timeout=5導(dǎo)致所有跨洋請(qǐng)求必然超時(shí)(實(shí)際平均響應(yīng)時(shí)間8秒)
  • 暴力重試雪崩:簡單for循環(huán)重試5次,瞬間產(chǎn)生10倍請(qǐng)求量擊垮順豐網(wǎng)關(guān)
  • 代理池污染:使用失效代理IP發(fā)起請(qǐng)求,觸發(fā)順豐反爬機(jī)制封禁整個(gè)IP段

這些場景揭示核心問題:API請(qǐng)求需要"有智慧的等待"和"有策略的堅(jiān)持" 。

二、超時(shí)配置:給請(qǐng)求裝上"安全閥"

1. 連接超時(shí) vs 讀取超時(shí)

import requests

try:
    # 連接超時(shí)3秒(TCP握手階段)
    # 讀取超時(shí)10秒(服務(wù)器處理階段)
    response = requests.get(
        'https://api.sf-express.com/track',
        params={'trackingNumber': 'SF123456789'},
        timeout=(3, 10)  # 元組形式分別設(shè)置
    )
    print(response.json())
except requests.exceptions.ConnectTimeout:
    print("連接服務(wù)器失敗,請(qǐng)檢查網(wǎng)絡(luò)")
except requests.exceptions.ReadTimeout:
    print("服務(wù)器處理超時(shí),請(qǐng)稍后重試")

關(guān)鍵決策點(diǎn)

  • 國內(nèi)API調(diào)用:timeout=(2, 5)(連接2秒,讀取5秒)
  • 跨境API調(diào)用:timeout=(5, 15)(考慮國際鏈路延遲)
  • 文件上傳場景:需增加write_timeout參數(shù)(需httpx等庫支持)

2. 動(dòng)態(tài)超時(shí)策略

某物流監(jiān)控系統(tǒng)采用分級(jí)超時(shí)機(jī)制:

def get_dynamic_timeout(retry_count):
    base_timeout = 3  # 基礎(chǔ)超時(shí)
    if retry_count > 0:
        return min(base_timeout * (2 ** retry_count), 30)  # 指數(shù)退避,最大30秒
    return base_timeout

# 使用示例
for i in range(3):
    try:
        timeout = get_dynamic_timeout(i)
        response = requests.get(url, timeout=timeout)
        break
    except Exception as e:
        print(f"第{i+1}次嘗試失敗,超時(shí)時(shí)間調(diào)整為{timeout}秒")

三、重試機(jī)制:讓請(qǐng)求學(xué)會(huì)"堅(jiān)持"

1. 指數(shù)退避重試(推薦方案)

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_retry_session(retries=3, backoff_factor=1, status_forcelist=(500, 502, 503, 504)):
    session = requests.Session()
    retry = Retry(
        total=retries,
        read=True,  # 允許讀取超時(shí)重試
        connect=True,  # 允許連接超時(shí)重試
        backoff_factor=backoff_factor,
        status_forcelist=status_forcelist,
        allowed_methods=["GET", "POST"]  # 支持POST請(qǐng)求重試
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    return session

# 使用示例
session = create_retry_session()
response = session.get('https://api.sf-express.com/track', params={'trackingNumber': 'SF123456789'})

參數(shù)深解:

  • backoff_factor=1:第1次重試等待1秒,第2次2秒,第3次4秒
  • status_forcelist:僅對(duì)5xx服務(wù)器錯(cuò)誤和429限流錯(cuò)誤重試
  • allowed_methods:默認(rèn)不重試POST請(qǐng)求,需顯式聲明

2. 熔斷機(jī)制實(shí)現(xiàn)(避免雪崩)

from collections import deque
import time

class CircuitBreaker:
    def __init__(self, max_failures=3, reset_timeout=60):
        self.failures = deque(maxlen=max_failures)
        self.reset_timeout = reset_timeout

    def is_open(self):
        if len(self.failures) < self.failures.maxlen:
            return False
        # 如果最近max_failures次請(qǐng)求都失敗,且最后一次失敗在reset_timeout秒內(nèi)
        return (time.time() - self.failures[-1]) < self.reset_timeout

    def record_failure(self):
        self.failures.append(time.time())

    def record_success(self):
        self.failures.clear()

# 結(jié)合重試使用
breaker = CircuitBreaker(max_failures=3, reset_timeout=30)

def safe_request():
    if breaker.is_open():
        raise Exception("Service unavailable, circuit breaker open")
    
    try:
        response = create_retry_session().get(url)
        if response.status_code == 200:
            breaker.record_success()
            return response
        else:
            breaker.record_failure()
            raise Exception("API request failed")
    except Exception as e:
        breaker.record_failure()
        raise e

四、代理配置:突破封禁的"隱身術(shù)"

1. 代理池實(shí)戰(zhàn)方案

import random
from requests.adapters import HTTPAdapter

class ProxyPool:
    def __init__(self):
        self.proxies = [
            {"http": "http://1.1.1.1:8080", "https": "http://1.1.1.1:8080"},
            {"http": "http://2.2.2.2:8080", "https": "http://2.2.2.2:8080"},
            # 更多代理...
        ]
        self.failed_proxies = set()

    def get_proxy(self):
        available_proxies = [p for p in self.proxies if p not in self.failed_proxies]
        if not available_proxies:
            raise Exception("No available proxies")
        return random.choice(available_proxies)

    def mark_failed(self, proxy):
        self.failed_proxies.add(proxy)

# 使用示例
proxy_pool = ProxyPool()
session = requests.Session()

for _ in range(3):  # 嘗試3個(gè)不同代理
    try:
        proxy = proxy_pool.get_proxy()
        response = session.get(
            'https://api.sf-express.com/track',
            proxies=proxy,
            timeout=(3, 10)
        )
        if response.status_code == 200:
            print("Success with proxy:", proxy)
            break
        else:
            proxy_pool.mark_failed(proxy)
    except Exception:
        proxy_pool.mark_failed(proxy)
else:
    print("All proxies failed")

2. Tor代理配置(高匿名場景)

import requests

def make_tor_request(url):
    proxies = {
        'http': 'socks5h://127.0.0.1:9050',
        'https': 'socks5h://127.0.0.1:9050'
    }
    try:
        response = requests.get(url, proxies=proxies, timeout=(5, 15))
        print("Tor出口IP:", response.json()['origin'])
        return response
    except Exception as e:
        print("Tor請(qǐng)求失敗:", e)

# 需提前安裝Tor服務(wù)并啟動(dòng)
# sudo apt install tor  # Ubuntu系統(tǒng)
# sudo service tor start

五、完整實(shí)戰(zhàn)案例

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import logging
from datetime import datetime

# 日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class SFExpressTracker:
    def __init__(self, app_key, app_secret):
        self.app_key = app_key
        self.app_secret = app_secret
        self.session = self._create_session()

    def _create_session(self):
        """創(chuàng)建帶重試和超時(shí)的會(huì)話"""
        retry_strategy = Retry(
            total=3,
            backoff_factor=1,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["GET", "POST"]
        )
        adapter = HTTPAdapter(max_retries=retry_strategy)
        session = requests.Session()
        session.mount("http://", adapter)
        session.mount("https://", adapter)
        return session

    def _generate_sign(self, params):
        """生成API簽名(簡化版)"""
        import hashlib
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        raw_str = self.app_secret + ''.join([f"{k}{v}" for k, v in sorted_params]) + self.app_secret
        return hashlib.md5(raw_str.encode()).hexdigest().upper()

    def query_track(self, tracking_number):
        """查詢物流軌跡"""
        url = "https://bsp-ois.sf-express.com/bsp-ois/express/service/queryTrack"
        params = {
            "appKey": self.app_key,
            "trackNumber": tracking_number,
            "timestamp": str(int(datetime.now().timestamp()))
        }
        params["sign"] = self._generate_sign(params)

        try:
            response = self.session.get(
                url,
                params=params,
                timeout=(3, 10)  # 連接3秒,讀取10秒
            )
            response.raise_for_status()
            data = response.json()
            
            if data.get('success'):
                return data['data']['tracks']
            else:
                logging.warning(f"API返回錯(cuò)誤: {data.get('errorMsg', '未知錯(cuò)誤')}")
                return None
                
        except requests.exceptions.RequestException as e:
            logging.error(f"請(qǐng)求失敗: {str(e)}")
            return None

# 使用示例
if __name__ == "__main__":
    tracker = SFExpressTracker(app_key="YOUR_APP_KEY", app_secret="YOUR_APP_SECRET")
    tracks = tracker.query_track("SF123456789")
    if tracks:
        for step in tracks:
            print(f"{step['acceptTime']} {step['acceptAddress']} - {step['remark']}")

六、常見問題Q&A

Q1:被網(wǎng)站封IP怎么辦?

A:立即啟用備用代理池,建議使用住宅代理(如站大爺IP代理),配合每請(qǐng)求更換IP策略。對(duì)于大規(guī)模爬取,可采用Tor網(wǎng)絡(luò)或IP輪換中間件。

Q2:如何選擇重試次數(shù)?

A:遵循"3次黃金法則":

  • 首次請(qǐng)求
  • 指數(shù)退避重試2次(總計(jì)3次)
  • 超過3次仍失敗應(yīng)觸發(fā)熔斷或人工干預(yù)

Q3:代理請(qǐng)求速度慢怎么解決?

A:

  • 測試代理延遲:curl --socks5 127.0.0.1:9050 https://httpbin.org/ip
  • 使用代理評(píng)分機(jī)制,淘汰高延遲代理
  • 對(duì)代理請(qǐng)求添加User-Agent和常規(guī)請(qǐng)求頭

Q4:如何記錄重試日志?

A:擴(kuò)展Retry類實(shí)現(xiàn)自定義日志:

from urllib3.util.retry import Retry
import logging

class LoggingRetry(Retry):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.logger = logging.getLogger(__name__)

    def new(self, **kw):
        self.logger.debug(f"Creating new retry adapter with params: {kw}")
        return super().new(**kw)

    def increment(self, method, url, response=None, error=None, **kwargs):
        self.logger.warning(f"Retry attempt {self.total - self._remaining + 1} for {method} {url}")
        return super().increment(method, url, response, error, **kwargs)

Q5:POST請(qǐng)求重試需要注意什么?

A:

  • 確保請(qǐng)求是冪等的(如使用唯一請(qǐng)求ID)
  • 在重試前檢查響應(yīng)是否已部分處理
  • 考慮使用idempotency-key請(qǐng)求頭(如Stripe API要求)

通過合理組合超時(shí)配置、智能重試和代理策略,可構(gòu)建出應(yīng)對(duì)各種異常場景的健壯API請(qǐng)求系統(tǒng)。實(shí)際開發(fā)中建議結(jié)合Prometheus監(jiān)控重試率、失敗率等指標(biāo),持續(xù)優(yōu)化請(qǐng)求策略。

以上就是Python Requests實(shí)現(xiàn)API請(qǐng)求重試與超時(shí)配置全解析的詳細(xì)內(nèi)容,更多關(guān)于Python Requests請(qǐng)求重試與超時(shí)配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python報(bào)錯(cuò)TypeError: ‘dict‘ object is not iterable的解決方法

    Python報(bào)錯(cuò)TypeError: ‘dict‘ object is not&

    在Python開發(fā)的旅程中,報(bào)錯(cuò)信息就像是一個(gè)個(gè)路障,阻礙著我們前進(jìn)的步伐,而“TypeError: ‘dict’ object is not iterable”這個(gè)報(bào)錯(cuò),常常讓開發(fā)者們陷入困惑,那么,這個(gè)報(bào)錯(cuò)究竟是怎么產(chǎn)生的呢?又該如何有效地解決它呢?讓我們一起深入探討,找到解決問題的方法
    2024-10-10
  • 使用Python防止SQL注入攻擊的實(shí)現(xiàn)示例

    使用Python防止SQL注入攻擊的實(shí)現(xiàn)示例

    這篇文章主要介紹了使用Python防止SQL注入攻擊的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • python Pandas中數(shù)據(jù)的合并與分組聚合

    python Pandas中數(shù)據(jù)的合并與分組聚合

    大家好,本篇文章主要講的是python Pandas中數(shù)據(jù)的合并與分組聚合,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • 精確查找PHP WEBSHELL木馬的方法(1)

    精確查找PHP WEBSHELL木馬的方法(1)

    今天,我想了下,現(xiàn)在把查找PHP WEBSHELL木馬思路發(fā)出來,需要的朋友可以參考下。
    2011-04-04
  • 能讓你輕松的實(shí)現(xiàn)自然語言處理的5個(gè)Python庫

    能讓你輕松的實(shí)現(xiàn)自然語言處理的5個(gè)Python庫

    今天教大家如何你輕松的實(shí)現(xiàn)自然語言預(yù)處理,僅僅需要5個(gè)python庫,文中介紹的非常詳細(xì),對(duì)正在學(xué)習(xí)python的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • Python+Qt身體特征識(shí)別人數(shù)統(tǒng)計(jì)源碼窗體程序(使用步驟)

    Python+Qt身體特征識(shí)別人數(shù)統(tǒng)計(jì)源碼窗體程序(使用步驟)

    這篇文章主要介紹了Python+Qt身體特征識(shí)別人數(shù)統(tǒng)計(jì)源碼窗體程序(使用步驟),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • Python中的Pandas庫操作小結(jié)

    Python中的Pandas庫操作小結(jié)

    Pandas 是一個(gè)用于數(shù)據(jù)分析的 Python 第三方庫,能夠處理和分析不同格式的數(shù)據(jù),Pandas 提供了兩種數(shù)據(jù)結(jié)構(gòu),分別為 Series 和 DataFrame,靈活而方便地進(jìn)行數(shù)據(jù)分析和操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-06-06
  • Python代碼列表求并集,交集,差集

    Python代碼列表求并集,交集,差集

    這篇文章主要介紹了Python代碼列表求并集,交集,差集,下面文章講詳細(xì)的介紹如何利用python代碼實(shí)現(xiàn)并集,交集,差集的相關(guān)資料展開內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • Python上級(jí)目錄文件導(dǎo)入的幾種方法(from.import)

    Python上級(jí)目錄文件導(dǎo)入的幾種方法(from.import)

    有時(shí)候我們可能需要import另一個(gè)路徑下的python文件,下面這篇文章主要給大家介紹了關(guān)于Python上級(jí)目錄文件導(dǎo)入的幾種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • 教你使用Python建立任意層數(shù)的深度神經(jīng)網(wǎng)絡(luò)

    教你使用Python建立任意層數(shù)的深度神經(jīng)網(wǎng)絡(luò)

    這篇文章主要介紹了Python建立任意層數(shù)的深度神經(jīng)網(wǎng)絡(luò),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08

最新評(píng)論

罗源县| 桐庐县| 大埔县| 航空| 乐清市| 铁岭县| 彝良县| 额尔古纳市| 佛坪县| 来安县| 商水县| 衡水市| 祁门县| 赤城县| 泸西县| 宁陕县| 安陆市| 湘潭市| 平果县| 德保县| 咸宁市| 信阳市| 济阳县| 石首市| 光山县| 太仆寺旗| 古田县| 嵊州市| 平潭县| 阳泉市| 定州市| 平遥县| 伊川县| 宝应县| 娱乐| 永济市| 繁昌县| 盱眙县| 芷江| 措美县| 西青区|