Einführung
Dieses Tutorial führt Sie durch die Behandlung verschiedener HTTP-Statuscodes in Python-Requests. HTTP-Statuscodes sind essentiell, um zu verstehen, ob eine Webanfrage erfolgreich war oder fehlgeschlagen ist, und wie man angemessen auf verschiedene Szenarien reagiert. Am Ende dieses Labors werden Sie lernen, wie Sie eine robuste Fehlerbehandlung in Ihren Python-Anwendungen implementieren, die mit Webdiensten interagieren.
Sie beginnen mit dem Verständnis von HTTP-Statuscodes und bauen dann schrittweise Ihre Fähigkeiten auf, indem Sie grundlegende und fortgeschrittene Fehlerbehandlungstechniken implementieren. Dieses Wissen ist entscheidend für die Entwicklung zuverlässiger Python-Webanwendungen, die auf verschiedene Serverantworten elegant reagieren.
HTTP-Statuscodes verstehen und einrichten
Was sind HTTP-Statuscodes?
HTTP-Statuscodes sind dreistellige Zahlen, die von einem Server als Antwort auf eine Anfrage eines Clients zurückgegeben werden. Sie geben an, ob eine bestimmte HTTP-Anfrage erfolgreich abgeschlossen wurde. Diese Codes sind in fünf Kategorien unterteilt:
- 1xx (Informationell): Die Anfrage wurde empfangen, und der Prozess wird fortgesetzt
- 2xx (Erfolg): Die Anfrage wurde erfolgreich empfangen, verstanden und akzeptiert
- 3xx (Umleitung): Es müssen weitere Maßnahmen ergriffen werden, um die Anfrage abzuschließen
- 4xx (Client-Fehler): Die Anfrage enthält eine fehlerhafte Syntax oder kann nicht erfüllt werden
- 5xx (Server-Fehler): Der Server konnte eine scheinbar gültige Anfrage nicht erfüllen
Häufige Statuscodes, denen Sie begegnen werden, sind:
| Statuscode | Name | Beschreibung |
|---|---|---|
| 200 | OK | Anfrage erfolgreich |
| 201 | Created | Anfrage erfolgreich und Ressource erstellt |
| 400 | Bad Request | Server kann die Anfrage nicht verarbeiten |
| 401 | Unauthorized | Authentifizierung ist erforderlich |
| 404 | Not Found | Die angeforderte Ressource konnte nicht gefunden werden |
| 500 | Internal Server Error | Der Server ist auf einen unerwarteten Zustand gestoßen |
Einrichten Ihrer Python-Umgebung
Bevor wir mit der Behandlung von HTTP-Statuscodes beginnen, installieren wir die Python requests-Bibliothek und erstellen ein einfaches Testskript.
- Öffnen Sie ein Terminal in der LabEx-Umgebung und führen Sie aus:
pip install requests
- Erstellen Sie ein neues Verzeichnis für unsere Projektdateien:
mkdir -p ~/project/http_status_lab
cd ~/project/http_status_lab
- Erstellen Sie mit der WebIDE eine neue Datei namens
test_request.pyim Verzeichnishttp_status_labmit diesem Basicode:
import requests
def make_request(url):
"""Make a basic GET request to the specified URL."""
response = requests.get(url)
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text[:100]}...") ## Print first 100 characters
return response
## Test with a working URL
response = make_request("https://httpbin.org/status/200")
print(f"Request was successful: {response.ok}")
- Führen Sie das Testskript aus, um es in Aktion zu sehen:
python test_request.py
Sie sollten eine Ausgabe ähnlich dieser sehen:
Status Code: 200
Response: ...
Request was successful: True
Dies bestätigt, dass Sie die Python-Umgebung erfolgreich eingerichtet haben und grundlegende HTTP-Anfragen stellen können. In den nächsten Schritten lernen Sie, wie Sie verschiedene HTTP-Statuscodes behandeln und fortgeschrittenere Fehlerbehandlungstechniken implementieren.
Umgang mit grundlegenden HTTP-Statuscodes
Nachdem Sie nun verstanden haben, was HTTP-Statuscodes sind und Ihre Umgebung eingerichtet haben, wollen wir eine grundlegende Fehlerbehandlung für gängige Statuscodes implementieren.
Erstellen eines Statuscode-Testwerkzeugs
Zuerst erstellen wir ein Werkzeug, mit dem wir verschiedene HTTP-Statuscodes testen können. Die Website httpbin.org bietet Endpunkte, die bestimmte Statuscodes zurückgeben, was sich perfekt für unsere Tests eignet.
Erstellen Sie eine neue Datei namens status_code_tester.py in Ihrem Verzeichnis http_status_lab mit dem folgenden Code:
import requests
import sys
def test_status_code(status_code):
"""Test a specific HTTP status code using httpbin.org."""
url = f"https://httpbin.org/status/{status_code}"
try:
response = requests.get(url)
print(f"Status Code: {response.status_code}")
print(f"Response OK: {response.ok}")
return response
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
if __name__ == "__main__":
## Get status code from command line or use default
status_code = sys.argv[1] if len(sys.argv) > 1 else "200"
test_status_code(status_code)
Dieses Skript sendet eine Anfrage an httpbin.org mit einem bestimmten Statuscode und gibt das Ergebnis aus. Sie können es mit einem Befehlszeilenargument ausführen, um verschiedene Statuscodes zu testen.
Testen verschiedener Statuscodes
Testen wir unser Skript mit verschiedenen Statuscodes, um zu sehen, wie die requests-Bibliothek damit umgeht:
- Testen Sie eine erfolgreiche Anfrage (200 OK):
python status_code_tester.py 200
Erwartete Ausgabe:
Status Code: 200
Response OK: True
- Testen Sie einen Client-Fehler (404 Not Found):
python status_code_tester.py 404
Erwartete Ausgabe:
Status Code: 404
Response OK: False
- Testen Sie einen Server-Fehler (500 Internal Server Error):
python status_code_tester.py 500
Erwartete Ausgabe:
Status Code: 500
Response OK: False
Umgang mit grundlegenden Statuscode-Kategorien
Nun erstellen wir ein umfassenderes Skript, das verschiedene Kategorien von Statuscodes angemessen behandelt. Erstellen Sie eine neue Datei namens basic_handler.py in Ihrem Verzeichnis http_status_lab:
import requests
def handle_response(url):
"""Handle different HTTP status codes with basic error handling."""
try:
response = requests.get(url)
## Check status code category
if 200 <= response.status_code < 300:
print(f"Success! Status code: {response.status_code}")
return response
elif 300 <= response.status_code < 400:
print(f"Redirection! Status code: {response.status_code}")
## For redirection, you might want to follow the redirect
return response
elif 400 <= response.status_code < 500:
print(f"Client error! Status code: {response.status_code}")
## Handle client errors
return response
elif 500 <= response.status_code < 600:
print(f"Server error! Status code: {response.status_code}")
## Handle server errors
return response
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
## Test with different status codes
print("Testing 200 OK:")
handle_response("https://httpbin.org/status/200")
print("\nTesting 404 Not Found:")
handle_response("https://httpbin.org/status/404")
print("\nTesting 500 Internal Server Error:")
handle_response("https://httpbin.org/status/500")
Führen Sie das Skript aus, um zu sehen, wie es mit verschiedenen Statuscodes umgeht:
python basic_handler.py
Erwartete Ausgabe:
Testing 200 OK:
Success! Status code: 200
Testing 404 Not Found:
Client error! Status code: 404
Testing 500 Internal Server Error:
Server error! Status code: 500
Dieser grundlegende Handler gruppiert Statuscodes in Kategorien und ergreift je nach Kategorie unterschiedliche Maßnahmen. Dies ist ein gängiges Muster in Python-Webanwendungen, mit dem Sie verschiedene Arten von Antworten angemessen behandeln können.
Implementierung erweiterter Fehlerbehandlung
Nachdem Sie nun die Grundlagen der Behandlung von HTTP-Statuscodes verstanden haben, wollen wir erweiterte Fehlerbehandlungstechniken für Ihre Python-Anwendungen implementieren.
Verwendung von raise_for_status()
Die requests-Bibliothek bietet eine praktische Methode namens raise_for_status(), die eine Ausnahme für 4xx- und 5xx-Statuscodes auslöst. Dies ist eine einfache, aber effektive Methode zur Fehlerbehandlung in Ihrem Code.
Erstellen Sie eine neue Datei namens raise_for_status_example.py in Ihrem Verzeichnis http_status_lab:
import requests
def fetch_data(url):
"""Fetch data from a URL with error handling using raise_for_status()."""
try:
response = requests.get(url)
## This will raise an HTTPError if the HTTP request returned an unsuccessful status code
response.raise_for_status()
## If we get here, the request was successful
print(f"Success! Status code: {response.status_code}")
return response.json() if 'application/json' in response.headers.get('Content-Type', '') else response.text
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e}")
return None
except requests.exceptions.ConnectionError as e:
print(f"Connection Error: {e}")
return None
except requests.exceptions.Timeout as e:
print(f"Timeout Error: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"Request Exception: {e}")
return None
## Test with different URLs
print("Testing successful request:")
data = fetch_data("https://httpbin.org/json")
print(f"Received data type: {type(data)}")
print("\nTesting 404 error:")
data = fetch_data("https://httpbin.org/status/404")
print(f"Received data: {data}")
print("\nTesting 500 error:")
data = fetch_data("https://httpbin.org/status/500")
print(f"Received data: {data}")
Führen Sie das Skript aus, um zu sehen, wie raise_for_status() Fehler behandelt:
python raise_for_status_example.py
Die erwartete Ausgabe zeigt, dass die Bibliothek automatisch Ausnahmen für Nicht-2xx-Statuscodes auslöst, die Ihr Code dann abfangen und entsprechend behandeln kann.
Erstellen benutzerdefinierter Ausnahmebehandler
Für komplexere Anwendungen möchten Sie möglicherweise benutzerdefinierte Ausnahmebehandler erstellen, um eine spezifischere Fehlerbehandlung zu ermöglichen. Erstellen wir ein fortgeschritteneres Beispiel:
Erstellen Sie eine neue Datei namens custom_exception_handler.py in Ihrem Verzeichnis http_status_lab:
import requests
import logging
## Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
## Custom exceptions
class APIError(Exception):
"""Base class for API request exceptions."""
pass
class ClientError(APIError):
"""Exception raised for client errors (4xx)."""
pass
class ServerError(APIError):
"""Exception raised for server errors (5xx)."""
pass
class NotFoundError(ClientError):
"""Exception raised for 404 Not Found errors."""
pass
class UnauthorizedError(ClientError):
"""Exception raised for 401 Unauthorized errors."""
pass
def api_request(url, method="get", **kwargs):
"""Make an API request with comprehensive error handling."""
try:
## Make the request using the specified HTTP method
response = getattr(requests, method.lower())(url, **kwargs)
## Log the response status
logger.info(f"Request to {url} returned status code {response.status_code}")
## Handle different status codes
if 200 <= response.status_code < 300:
return response
elif response.status_code == 401:
raise UnauthorizedError(f"Authentication required: {response.text}")
elif response.status_code == 404:
raise NotFoundError(f"Resource not found: {url}")
elif 400 <= response.status_code < 500:
raise ClientError(f"Client error {response.status_code}: {response.text}")
elif 500 <= response.status_code < 600:
raise ServerError(f"Server error {response.status_code}: {response.text}")
else:
raise APIError(f"Unexpected status code {response.status_code}: {response.text}")
except requests.exceptions.RequestException as e:
logger.error(f"Request failed: {e}")
raise APIError(f"Request failed: {e}")
## Test the custom exception handler
def test_api_request(url):
"""Test the api_request function with error handling."""
try:
response = api_request(url)
print(f"Success! Status code: {response.status_code}")
print(f"Response: {response.text[:100]}...") ## Print first 100 characters
return response
except UnauthorizedError as e:
print(f"Authentication Error: {e}")
except NotFoundError as e:
print(f"Not Found Error: {e}")
except ClientError as e:
print(f"Client Error: {e}")
except ServerError as e:
print(f"Server Error: {e}")
except APIError as e:
print(f"API Error: {e}")
return None
## Test with different status codes
print("Testing 200 OK:")
test_api_request("https://httpbin.org/status/200")
print("\nTesting 404 Not Found:")
test_api_request("https://httpbin.org/status/404")
print("\nTesting 401 Unauthorized:")
test_api_request("https://httpbin.org/status/401")
print("\nTesting 500 Internal Server Error:")
test_api_request("https://httpbin.org/status/500")
Führen Sie das Skript aus, um zu sehen, wie die benutzerdefinierte Ausnahmebehandlung funktioniert:
python custom_exception_handler.py
Dieses erweiterte Beispiel demonstriert mehrere wichtige Konzepte:
- Benutzerdefinierte Ausnahmeklassen, die die Basisklasse
Exceptionerweitern - Hierarchische Ausnahmen für verschiedene Arten von Fehlern
- Detaillierte Protokollierung für Debugging und Überwachung
- Spezifische Behandlung für verschiedene Statuscodes
Dieser Ansatz ermöglicht es Ihnen, verschiedene Fehlertypen strukturierter und wartbarer zu behandeln, was für größere Anwendungen unerlässlich ist.
Erstellen eines vollständigen Web-API-Clients
In diesem letzten Schritt werden wir alles, was Sie gelernt haben, zusammenführen, um einen vollständigen Web-API-Client mit robuster Fehlerbehandlung zu erstellen. Wir erstellen einen Client für die JSONPlaceholder-API, eine kostenlose Online-REST-API, die Sie zum Testen verwenden können.
Erstellen eines einfachen API-Clients
Erstellen wir eine Datei namens api_client.py in Ihrem Verzeichnis http_status_lab:
import requests
import json
import logging
## Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class APIClient:
"""A simple API client with robust error handling."""
def __init__(self, base_url):
"""Initialize the API client with a base URL."""
self.base_url = base_url
self.session = requests.Session()
def request(self, endpoint, method="get", params=None, data=None, headers=None):
"""Make a request to the API with error handling."""
url = f"{self.base_url}{endpoint}"
## Default headers for JSON APIs
if headers is None:
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
## Convert data to JSON if it's a dictionary
json_data = None
if data and isinstance(data, dict):
json_data = data
data = None
try:
## Log the request
logger.info(f"Making {method.upper()} request to {url}")
## Make the request
response = self.session.request(
method=method,
url=url,
params=params,
data=data,
json=json_data,
headers=headers
)
## Log the response status
logger.info(f"Received response with status code {response.status_code}")
## Check for HTTP errors
response.raise_for_status()
## Parse JSON response if applicable
try:
return response.json()
except json.JSONDecodeError:
return response.text
except requests.exceptions.HTTPError as e:
status_code = e.response.status_code
error_message = f"HTTP Error: {status_code}"
try:
## Try to get more details from the response
error_data = e.response.json()
error_message = f"{error_message} - {error_data.get('message', str(error_data))}"
except (json.JSONDecodeError, AttributeError):
error_message = f"{error_message} - {e.response.text if hasattr(e, 'response') else str(e)}"
logger.error(error_message)
## Re-raise with more context
if 400 <= status_code < 500:
logger.error(f"Client error: {error_message}")
raise Exception(f"Client error (HTTP {status_code}): {error_message}")
elif 500 <= status_code < 600:
logger.error(f"Server error: {error_message}")
raise Exception(f"Server error (HTTP {status_code}): {error_message}")
else:
raise
except requests.exceptions.ConnectionError as e:
logger.error(f"Connection Error: {e}")
raise Exception(f"Connection Error: Could not connect to {url}")
except requests.exceptions.Timeout as e:
logger.error(f"Timeout Error: {e}")
raise Exception(f"Timeout Error: Request to {url} timed out")
except requests.exceptions.RequestException as e:
logger.error(f"Request Exception: {e}")
raise Exception(f"Request Error: {str(e)}")
def get(self, endpoint, params=None, headers=None):
"""Make a GET request to the API."""
return self.request(endpoint, method="get", params=params, headers=headers)
def post(self, endpoint, data=None, headers=None):
"""Make a POST request to the API."""
return self.request(endpoint, method="post", data=data, headers=headers)
def put(self, endpoint, data=None, headers=None):
"""Make a PUT request to the API."""
return self.request(endpoint, method="put", data=data, headers=headers)
def delete(self, endpoint, headers=None):
"""Make a DELETE request to the API."""
return self.request(endpoint, method="delete", headers=headers)
## Test the API client with JSONPlaceholder
def test_api_client():
"""Test the API client with JSONPlaceholder."""
client = APIClient("https://jsonplaceholder.typicode.com")
try:
## Get a list of posts
print("\nGetting posts:")
posts = client.get("/posts")
print(f"Retrieved {len(posts)} posts")
print(f"First post: {posts[0]}")
## Get a single post
print("\nGetting a single post:")
post = client.get("/posts/1")
print(f"Retrieved post: {post}")
## Get a non-existent post (404)
print("\nTrying to get a non-existent post:")
try:
client.get("/posts/999999")
except Exception as e:
print(f"Expected error: {e}")
## Create a new post
print("\nCreating a new post:")
new_post = client.post("/posts", {
"title": "My New Post",
"body": "This is the content of my new post.",
"userId": 1
})
print(f"Created post: {new_post}")
## Update a post
print("\nUpdating a post:")
updated_post = client.put("/posts/1", {
"id": 1,
"title": "Updated Title",
"body": "Updated content.",
"userId": 1
})
print(f"Updated post: {updated_post}")
## Delete a post
print("\nDeleting a post:")
delete_response = client.delete("/posts/1")
print(f"Delete response: {delete_response}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
test_api_client()
Führen Sie das Skript aus, um zu sehen, wie unser vollständiger API-Client verschiedene Szenarien behandelt:
python api_client.py
Testen der Fehlerbehandlung
Erstellen wir eine separate Datei, um die Fehlerbehandlungsfähigkeiten unseres API-Clients zu testen. Erstellen Sie eine Datei namens test_error_handling.py in Ihrem Verzeichnis http_status_lab:
from api_client import APIClient
import time
def test_different_errors():
"""Test different error scenarios with our API client."""
## Test with a valid API
print("\n1. Testing with a valid API:")
valid_client = APIClient("https://jsonplaceholder.typicode.com")
try:
data = valid_client.get("/posts/1")
print(f"Success! Retrieved data: {data}")
except Exception as e:
print(f"Unexpected error: {e}")
## Test with a 404 error
print("\n2. Testing with a non-existent endpoint (404):")
try:
valid_client.get("/non_existent_endpoint")
except Exception as e:
print(f"Expected error: {e}")
## Test with an invalid host
print("\n3. Testing with an invalid host (Connection Error):")
invalid_client = APIClient("https://this-does-not-exist-123456789.com")
try:
invalid_client.get("/anything")
except Exception as e:
print(f"Expected error: {e}")
## Test with a timeout
print("\n4. Testing with a timeout:")
timeout_client = APIClient("https://httpbin.org")
try:
## httpbin.org/delay/5 will delay the response for 5 seconds
## but we'll set the timeout to 2 seconds
timeout_client.session.request = lambda **kwargs: timeout_client.session.request_original(
**{**kwargs, 'timeout': 2}
)
timeout_client.session.request_original = timeout_client.session.request
timeout_client.get("/delay/5")
except Exception as e:
print(f"Expected error: {e}")
if __name__ == "__main__":
test_different_errors()
Das obige Skript kann aufgrund der Timeout-Behandlung Fehler verursachen, da es versucht, eine Methode zur Laufzeit zu ändern. Vereinfachen wir es, um diese Probleme zu vermeiden:
from api_client import APIClient
def test_different_errors():
"""Test different error scenarios with our API client."""
## Test with a valid API
print("\n1. Testing with a valid API:")
valid_client = APIClient("https://jsonplaceholder.typicode.com")
try:
data = valid_client.get("/posts/1")
print(f"Success! Retrieved data: {data}")
except Exception as e:
print(f"Unexpected error: {e}")
## Test with a 404 error
print("\n2. Testing with a non-existent endpoint (404):")
try:
valid_client.get("/non_existent_endpoint")
except Exception as e:
print(f"Expected error: {e}")
## Test with a server error
print("\n3. Testing with a server error (500):")
error_client = APIClient("https://httpbin.org")
try:
error_client.get("/status/500")
except Exception as e:
print(f"Expected error: {e}")
if __name__ == "__main__":
test_different_errors()
Führen Sie das Fehler-Testskript aus:
python test_error_handling.py
Dieses Skript zeigt, wie unser API-Client verschiedene Fehlerszenarien behandelt und bietet eine robuste Grundlage für reale Anwendungen.
Wichtigste Erkenntnisse
Durch das Erstellen dieses vollständigen API-Clients haben Sie mehrere wichtige Techniken gelernt:
- Erstellen einer wiederverwendbaren API-Client-Klasse
- Implementierung einer umfassenden Fehlerbehandlung
- Protokollierung von Anfragen und Antworten zum Debuggen
- Parsen verschiedener Antwortformate
- Umgang mit verschiedenen HTTP-Methoden (GET, POST, PUT, DELETE)
Diese Fähigkeiten sind unerlässlich für das Erstellen robuster Python-Anwendungen, die mit Web-APIs interagieren, um sicherzustellen, dass Ihr Code verschiedene Fehlerszenarien problemlos behandeln und den Benutzern aussagekräftige Fehlermeldungen liefern kann.
Zusammenfassung
In diesem Lab haben Sie gelernt, wie man HTTP-Statuscodes in Python-Anfragen behandelt, wobei Sie von grundlegenden zu fortgeschrittenen Techniken übergegangen sind. Sie verfügen nun über die Fähigkeiten, um:
- Verschiedene Kategorien von HTTP-Statuscodes und ihre Bedeutungen zu verstehen
- Eine grundlegende Fehlerbehandlung mit Statuscode-Prüfung zu implementieren
raise_for_status()für eine einfache Fehlerbehandlung zu verwenden- Benutzerdefinierte Ausnahmeklassen für eine spezifischere Fehlerbehandlung zu erstellen
- Einen vollständigen API-Client mit umfassender Fehlerbehandlung zu erstellen
Diese Fähigkeiten sind unerlässlich für die Entwicklung robuster Python-Anwendungen, die mit Webdiensten interagieren. Durch die korrekte Behandlung von HTTP-Statuscodes und Fehlern können Sie zuverlässigere Anwendungen erstellen, die eine bessere Benutzererfahrung bieten und einfacher zu warten sind.
Denken Sie daran, bei der Arbeit mit HTTP-Anfragen in Ihren Python-Anwendungen immer die Fehlerbehandlung zu berücksichtigen. Sie ist ein entscheidender Aspekt der Webentwicklung, der professionellen Code von Amateur-Implementierungen unterscheidet.



