本文 AI 產出,尚未審核

Python 課程 – 網路與 API(Networking & APIs)

主題:RESTful API 呼叫


簡介

在現代軟體開發中,RESTful API 已成為前後端、微服務以及第三方服務之間最常使用的溝通方式。只要會呼叫 API,就能把資料從雲端服務、社群平台或公開資料庫即時取得,讓應用程式具備即時性與擴充性。
對於 Python 初學者而言,掌握如何正確、有效率地發送 HTTP 請求與處理回應,是進階開發路上不可或缺的基礎。本文將以 requests 套件為例,從概念說明到實作範例,帶你一步步完成安全、可維護的 RESTful 呼叫。


核心概念

1️⃣ HTTP 方法與資源定位

方法 語意 常見用途
GET 取得資源 讀取資料、搜尋
POST 建立資源 新增資料、觸發動作
PUT 完全取代資源 更新整筆資料
PATCH 部分更新 只改變部分欄位
DELETE 刪除資源 移除資料

每一次呼叫都需要一個 URL(統一資源定位符),它指向特定的資源,例如 https://api.example.com/users/123

2️⃣ 標頭(Headers)與認證

  • Content-Type:告訴伺服器傳送資料的格式,最常見的是 application/json
  • Authorization:放置 API 金鑰或 Bearer Token,用於驗證身分。
  • Accept:告訴伺服器希望收到的回應格式,通常也是 application/json
headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "Authorization": "Bearer YOUR_ACCESS_TOKEN"
}

3️⃣ 請求參數與資料格式

  • Query string(URL 參數): ?page=2&limit=20,適合 GET
  • Request body(請求主體): 以 JSON、form‑data 或 multipart 方式傳送,適合 POST / PUT / PATCH

4️⃣ 回應與狀態碼

狀態碼 說明
200 請求成功(GET)
201 成功建立(POST)
400 請求格式錯誤
401 未授權(認證失敗)
404 資源不存在
429 請求過於頻繁(Rate limit)
500 伺服器內部錯誤

重要:永遠先檢查 response.status_code,再根據需要呼叫 response.json()

5️⃣ 錯誤處理與重試機制

網路環境不穩定或第三方服務會臨時失效,重試(retry)逾時(timeout) 設定是必備的防護措施。


程式碼範例

以下示範 5 個實用範例,涵蓋 GET、POST、參數、錯誤處理與 Session 重用。所有範例皆使用 requests 套件,請先執行 pip install requests

1️⃣ 基本 GET 請求

import requests

url = "https://api.github.com/repos/python/cpython"
response = requests.get(url, timeout=5)   # 設定 5 秒逾時

if response.status_code == 200:
    data = response.json()                # 解析 JSON
    print(f"Repo 名稱: {data['full_name']}")
    print(f"星星數: {data['stargazers_count']}")
else:
    print(f"發生錯誤,狀態碼: {response.status_code}")

重點timeout 可以避免程式卡住;response.json() 只在回傳內容為 JSON 時才有效。

2️⃣ 搭配 Query Parameters 的 GET

import requests

url = "https://api.openweathermap.org/data/2.5/weather"
params = {
    "q": "Taipei,tw",
    "appid": "YOUR_API_KEY",   # 請自行申請
    "units": "metric"
}

resp = requests.get(url, params=params, timeout=10)
if resp.ok:                     # 等同於 200 <= status_code < 400
    weather = resp.json()
    print(f"目前溫度: {weather['main']['temp']}°C")
else:
    print(f"查詢失敗 ({resp.status_code})")

params 會自動轉換成 ?q=Taipei,tw&appid=... 並編碼。

3️⃣ POST JSON 資料(建立資源)

import requests
import json

url = "https://jsonplaceholder.typicode.com/posts"
payload = {
    "title": "測試文章",
    "body": "這是一段測試內容",
    "userId": 1
}
headers = {"Content-Type": "application/json"}

resp = requests.post(url, data=json.dumps(payload), headers=headers, timeout=5)

if resp.status_code == 201:
    result = resp.json()
    print(f"建立成功,ID 為 {result['id']}")
else:
    print(f"建立失敗 ({resp.status_code})")

小技巧json= 參數會自動幫你 json.dumps 並設定 Content-Type,寫法更簡潔:
requests.post(url, json=payload, timeout=5)

4️⃣ 使用 Session 與重試(Retry)機制

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

session = requests.Session()
retry_strategy = Retry(
    total=3,                     # 最多重試 3 次
    backoff_factor=1,           # 重試間隔 1, 2, 4 秒...
    status_forcelist=[429, 500, 502, 503, 504],
    method_whitelist=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)

try:
    resp = session.get("https://httpbin.org/status/503", timeout=5)
    resp.raise_for_status()     # 若仍非 2xx,拋出例外
    print("成功取得回應")
except requests.exceptions.RequestException as e:
    print(f"最終失敗:{e}")

Retry 能自動處理 5xx、429 等暫時失效的情形,減少手動寫迴圈的複雜度。

5️⃣ 下載檔案(串流)並顯示進度

import requests
from tqdm import tqdm   # pip install tqdm

url = "https://speed.hetzner.de/100MB.bin"
resp = requests.get(url, stream=True, timeout=10)

total = int(resp.headers.get('content-length', 0))
chunk_size = 1024 * 1024   # 1 MB
with open("100MB.bin", "wb") as f, tqdm(
        total=total, unit='iB', unit_scale=True) as bar:
    for chunk in resp.iter_content(chunk_size=chunk_size):
        f.write(chunk)
        bar.update(len(chunk))

print("下載完成")

使用 stream=True 可以避免一次把整個檔案載入記憶體,tqdm 則提供即時進度條,提升使用者體驗。


常見陷阱與最佳實踐

陷阱 說明 最佳做法
忘記檢查 status_code 直接呼叫 response.json() 會在非 2xx 時拋例外 使用 if response.ok:response.raise_for_status()
硬編碼 API 金鑰 代碼上直接寫 YOUR_API_KEY 會洩漏機密 把金鑰放在環境變數或 .env 檔,使用 os.getenv() 讀取
未設定逾時 請求卡住導致程式無回應 requests.get(..., timeout=5),依需求調整
忽略 SSL 驗證 verify=False 會降低安全性 除非測試環境,否則務必保持 verify=True
過度使用全局 Session 多執行緒共享同一 Session 可能產生競爭條件 為每個執行緒或任務建立獨立 Session,或使用 requests-futures
未處理 Rate Limit 被 429 限頻時直接失敗 捕捉 429,讀取 Retry-After 頭部,等待後重試

實際應用場景

  1. 整合第三方服務:在電商平台上使用 Stripe API 處理信用卡付款,只要把付款資訊 POST 給 Stripe,即可取得交易結果。
  2. 資料蒐集與分析:利用 Twitter API 抓取特定關鍵字的推文,結合 pandas 進行文字探勘與情感分析。
  3. 微服務間通訊:在大型系統中,前端服務透過 RESTful 呼叫後端的使用者服務(User Service),完成登入、註冊與權限驗證。
  4. 自動化測試:使用 pytest 搭配 requests-mock 模擬 API 回應,驗證程式在不同狀態碼下的行為。
  5. 檔案上傳/下載:在雲端儲存服務(如 AWS S3)使用 presigned URL 直接上傳大檔案,減少伺服器負載。

總結

  • RESTful API 是現代應用程式與服務互動的核心,掌握 HTTP 方法、標頭、參數與狀態碼是基礎。
  • Python 的 requests 套件提供直覺且功能完整的介面,配合 Sessiontimeoutretry 能寫出安全、可維護的網路程式。
  • 常見的陷阱(未檢查回應、硬編碼金鑰、忽略逾時)只要遵守 最佳實踐,即可大幅降低錯誤與資安風險。
  • 透過本文的範例,你已能 發送 GET/POST、處理 JSON、實作重試與檔案下載,接下來可以將這些技巧套用到實際的專案或第三方服務整合中。

祝你在 Python 網路開發的旅程中,玩得開心、寫得順手! 🚀