[Python API debugging] 用 urllib3 呼叫 API, 有時失敗、有時成功

更新 發佈閱讀 9 分鐘

Background

使用 Python 呼叫某第三方服務的 report API,希望取得一些資料來做廣告成效報表,初步使用 urllib3 來實作發送 HTTP 請求

遇到的問題

  • Local (Laptop) 環境,請求 API 失敗(返回 400 Error)
  • Production (Jenkins) 環境第一次成功,之後請求失敗(返回 400 Error)

Issue Analysis

使用 urllib3 時常失敗,但使用 curl 測試請求,發現可以穩定成功。

  • 代表 API 可能對 urllib3curl 回應的行為是不同的
  • 懷疑 API 服務對 Header 有流量或其他限制,另外 Return 400 error 感覺是工程師亂寫的,參考就好


嘗試方法:

  1. 使用 urllib3, 改 User-agent 可能有用
    • 可能的原因:實際上也有很多 API 服務,為了防爬蟲,會針對常見的 library 的 user-agent or connection 的方式有阻擋限制
  2. 直接改用 pycurl 方式連線
    • 可能的原因:urllib3 和 curl 的底層連線方式不同

pycurl vs. urllib3

vocus|新世代的創作平台


Solution

  1. 先在 urllib3 裡指定 User-Agent 到 curl, 但仍然不 work.
  2. 將原本 urllib3 的實作,改為 pycurl 的實作方式
  • urllib3
    # Default Header
    {
    "headers": {
    "Host": "httpbin.org",
    "Accept-Encoding": "identity",
    "User-Agent": "python-urllib3/1.26.16",
    "Accept": "*/*",
    "Connection": "close"
    }
    }
    # Example
    import urllib3
    from urllib3.util.retry import Retry
    from urllib3.exceptions import HTTPError
    import time

    # 設定重試機制
    retry_strategy = Retry(
    total=5, # 總共重試 5 次
    backoff_factor=1, # 每次失敗後等待時間 (1s, 2s, 4s, 8s, 16s...)
    status_forcelist=[500, 502, 503, 504], # 這些錯誤碼時才會重試
    allowed_methods=["GET"], # 只對 GET 方法啟用重試
    )

    # 建立連接池並套用重試策略
    http = urllib3.PoolManager(retries=retry_strategy)

    # 發送請求並加上錯誤處理
    def fetch_data(url):
    try:
    response = http.request("GET", url)
    response.raise_for_status() # 如果 HTTP 狀態碼錯誤,會拋出例外
    print(f"Status Code: {response.status}")
    print("Response Body:", response.data.decode("utf-8"))
    except HTTPError as e:
    print(f"HTTP 錯誤: {e}")
    except Exception as e:
    print(f"其他錯誤: {e}")

    # 執行 API 請求
    fetch_data(url = "<https://jsonplaceholder.typicode.com/posts/1>")


  • pycurl
    # Default header
    {
    "headers": {
    "Host": "httpbin.org",
    "User-Agent": "PycURL/7.43.0.6 libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11",
    "Accept": "*/*"
    }
    }
# Example
import pycurl
import certifi
import io
import time

# 最大重試次數
MAX_RETRIES = 5
BACKOFF_FACTOR = 1 # 每次失敗後等待 (1s, 2s, 4s, 8s, 16s)

def fetch_data(url):
retries = 0
while retries < MAX_RETRIES:
try:
buffer = io.BytesIO() # 用來存放回應的資料

# 設定 pycurl 參數
curl = pycurl.Curl()
curl.setopt(pycurl.URL, url) # 設定 URL
curl.setopt(pycurl.WRITEFUNCTION, buffer.write) # 把回應寫入 buffer
curl.setopt(pycurl.CAINFO, certifi.where()) # 設定 SSL 憑證
curl.setopt(pycurl.FOLLOWLOCATION, True) # 自動跟隨重定向

# 執行請求
curl.perform()

# 獲取 HTTP 狀態碼
status_code = curl.getinfo(pycurl.RESPONSE_CODE)
curl.close()

if status_code == 200:
print(f"Status Code: {status_code}")
print("Response Body:", buffer.getvalue().decode("utf-8"))
return
else:
raise Exception(f"HTTP 錯誤: {status_code}")

except Exception as e:
retries += 1
wait_time = BACKOFF_FACTOR * (2 ** (retries - 1))
print(f"第 {retries} 次重試: {e}, 等待 {wait_time} 秒")
time.sleep(wait_time)

print("請求失敗,已達最大重試次數")

# 執行 API 請求
fetch_data(url = "<https://jsonplaceholder.typicode.com/posts/1>")

留言
avatar-img
Alice Hsu的沙龍
0會員
1內容數
你可能也想看
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
見諸參與鄧伯宸口述,鄧湘庭於〈那個大霧的時代〉記述父親回憶,鄧伯宸因故遭受牽連,而案件核心的三人,在鄧伯宸記憶裡:「成立了成大共產黨,他們製作了五星徽章,印刷共產黨宣言——刻鋼板的——他們收集中共空飄的傳單,以及中國共產黨中央委員會有關文化大革命決議文的英文打字稿,另外還有手槍子彈十發。」
Thumbnail
見諸參與鄧伯宸口述,鄧湘庭於〈那個大霧的時代〉記述父親回憶,鄧伯宸因故遭受牽連,而案件核心的三人,在鄧伯宸記憶裡:「成立了成大共產黨,他們製作了五星徽章,印刷共產黨宣言——刻鋼板的——他們收集中共空飄的傳單,以及中國共產黨中央委員會有關文化大革命決議文的英文打字稿,另外還有手槍子彈十發。」
Thumbnail
API(Application Programming Interface,應用程式介面)可以視為不同軟體系統之間的溝通橋梁,讓雙邊可以交換數據並執行各種功能。這篇會記錄產品經理一定要知道的幾個 API 概念,像是常見的錯誤代碼以及不同的 HTTP 方法(如 PUT、GET、POST)和實際案例說明
Thumbnail
API(Application Programming Interface,應用程式介面)可以視為不同軟體系統之間的溝通橋梁,讓雙邊可以交換數據並執行各種功能。這篇會記錄產品經理一定要知道的幾個 API 概念,像是常見的錯誤代碼以及不同的 HTTP 方法(如 PUT、GET、POST)和實際案例說明
Thumbnail
呼叫API,並透過API響應的內容取到需要的值
Thumbnail
呼叫API,並透過API響應的內容取到需要的值
Thumbnail
這個問題發生在我們開發Python的Websocket Server時, 使用以下的程式碼架設服務 start_server = websockets.serve(server, 'localhost', args.port) async with start_server:
Thumbnail
這個問題發生在我們開發Python的Websocket Server時, 使用以下的程式碼架設服務 start_server = websockets.serve(server, 'localhost', args.port) async with start_server:
Thumbnail
在這一課中,我們將學習如何在Python中使用requests模塊發送HTTP請求。 發送GET請求requests.get() 函數用於發送GET請求。
Thumbnail
在這一課中,我們將學習如何在Python中使用requests模塊發送HTTP請求。 發送GET請求requests.get() 函數用於發送GET請求。
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
Thumbnail
上篇記錄了關於 HTTP request 的筆記,這篇則是對於請求的回應紀錄~
Thumbnail
上篇記錄了關於 HTTP request 的筆記,這篇則是對於請求的回應紀錄~
Thumbnail
這個章節雖然發生問題, 但也很好的為我們如何解決問題的能力而訓練, 我們也會搭配AI來幫我們找問題, 當然也會一五一十的告訴您該如何問對問題, 關於問對問題很重要可以參考「」, 我們相信過程會對大家有幫助, 請耐心閱讀…, 我們會告訴您AI說正確但事實上並非正確的情境。 我們在「【🔒 Pytho
Thumbnail
這個章節雖然發生問題, 但也很好的為我們如何解決問題的能力而訓練, 我們也會搭配AI來幫我們找問題, 當然也會一五一十的告訴您該如何問對問題, 關於問對問題很重要可以參考「」, 我們相信過程會對大家有幫助, 請耐心閱讀…, 我們會告訴您AI說正確但事實上並非正確的情境。 我們在「【🔒 Pytho
Thumbnail
當代名導基里爾.賽勒布倫尼科夫身兼電影、劇場與歌劇導演,其作品流動著強烈的反叛與詩意。在俄烏戰爭爆發後,他持續以創作回應專制體制的壓迫。《傳奇:帕拉贊諾夫的十段殘篇》致敬蘇聯電影大師帕拉贊諾夫。本文作者透過媒介本質的分析,解構賽勒布倫尼科夫如何利用影劇雙棲的特質,在荒謬世道中尋找藝術的「生存之道」。
Thumbnail
當代名導基里爾.賽勒布倫尼科夫身兼電影、劇場與歌劇導演,其作品流動著強烈的反叛與詩意。在俄烏戰爭爆發後,他持續以創作回應專制體制的壓迫。《傳奇:帕拉贊諾夫的十段殘篇》致敬蘇聯電影大師帕拉贊諾夫。本文作者透過媒介本質的分析,解構賽勒布倫尼科夫如何利用影劇雙棲的特質,在荒謬世道中尋找藝術的「生存之道」。
Thumbnail
在專案中與廠商測試API回傳的json字串出現無法解析的狀況,記錄發現過程與解決的紀錄,提供程式面和檔案面的解決方法。
Thumbnail
在專案中與廠商測試API回傳的json字串出現無法解析的狀況,記錄發現過程與解決的紀錄,提供程式面和檔案面的解決方法。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News