raise_for_status() și timeout în Python

HTTP și rețea requests 2.0+

Transformă răspunsurile de eroare (4xx, 5xx) în excepții și limitează cât așteaptă o cerere.

Sintaxă
r = requests.get(url, timeout=5)
r.raise_for_status()
except requests.exceptions.HTTPError / Timeout / ConnectionError / RequestException

Ce face raise_for_status() și timeout

requests nu dă eroare când serverul răspunde cu 404 sau 500: primești un răspuns normal, cu status_code diferit de 200. r.raise_for_status() verifică pentru tine: dacă codul este între 400 și 599, aruncă requests.exceptions.HTTPError; altfel nu face nimic.

timeout=5 oprește cererea dacă serverul nu se conectează sau nu trimite date timp de 5 secunde și aruncă requests.exceptions.Timeout. Poți da și un tuplu (3, 10): 3 secunde pentru conectare, 10 pentru citire. Fără rețea sau cu un nume de server greșit primești ConnectionError.

Toate aceste excepții moștenesc requests.exceptions.RequestException, pe care o poți prinde la final, pentru orice altă problemă de rețea.

Parametri

Parametru Descriere
timeout Număr de secunde sau tuplu (conectare, citire).
HTTPError Aruncată de raise_for_status() pentru codurile 4xx și 5xx.
Timeout Serverul nu a răspuns în timpul dat.
ConnectionError Nu s-a putut face conexiunea (fără rețea, nume greșit, server oprit).
RequestException Clasa de bază a tuturor excepțiilor requests.

Ce returnează

raise_for_status() returnează None sau aruncă HTTPError.

Exemple

Exemplul 1: Succes, eroare 404 și timeout

Adresa /delay/5 răspunde după 5 secunde, dar cererea așteaptă doar 2.

import requests

adrese = [
    "https://httpbin.org/status/200",
    "https://httpbin.org/status/404",
    "https://httpbin.org/delay/5",
]
for url in adrese:
    try:
        r = requests.get(url, timeout=2)
        r.raise_for_status()
        print("OK:", url)
    except requests.exceptions.HTTPError as e:
        print("Eroare HTTP:", e)
    except requests.exceptions.Timeout:
        print("Timeout:", url)

Rezultat posibil (diferă la fiecare rulare)

OK: https://httpbin.org/status/200
Eroare HTTP: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404
Timeout: https://httpbin.org/delay/5

Exemplul 2: O funcție care încearcă de mai multe ori

La erori de rețea sau timeout, funcția mai încearcă de două ori, apoi renunță. Erorile 4xx nu se reîncearcă: cererea e greșită.

import time
import requests

def descarca_curs(url, incercari=3):
    for incercare in range(1, incercari + 1):
        try:
            r = requests.get(url, timeout=(3, 10))
            r.raise_for_status()
            return r.json()
        except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
            print(f"Încercarea {incercare} a eșuat: {type(e).__name__}")
            time.sleep(1)
    raise RuntimeError("Serverul nu răspunde")

try:
    print(descarca_curs("https://server-care-nu-exista.ro/curs.json"))
except RuntimeError as e:
    print(e)

Rezultat posibil (diferă la fiecare rulare)

Încercarea 1 a eșuat: ConnectionError
Încercarea 2 a eșuat: ConnectionError
Încercarea 3 a eșuat: ConnectionError
Serverul nu răspunde

Greșeli frecvente

  • Presupui că un răspuns fără excepție înseamnă succes. Un 404 sau 500 nu aruncă nimic dacă nu apelezi raise_for_status() sau nu verifici status_code.
  • Prinzi except Exception peste tot și ascunzi și greșelile din propriul cod. Prinde excepțiile din requests.exceptions.
  • Crezi că timeout=10 limitează toată descărcarea la 10 secunde. Limitează așteptarea între două bucăți de date; o descărcare lentă, dar continuă, poate dura mai mult.

Comenzi înrudite

  • requests.get(): Trimite o cerere HTTP GET și returnează răspunsul: cod de stare, antete, text sau JSON.
  • requests.post(): Trimite date la un server prin HTTP POST: JSON pentru API-uri sau câmpuri de formular.
  • raise: Aruncă (semnalează) o excepție, oprind execuția normală până când este prinsă cu except.