Umgang mit verschiedenen HTTP-Statuscodes in Python-Requests

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

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.

  1. Öffnen Sie ein Terminal in der LabEx-Umgebung und führen Sie aus:
pip install requests
  1. Erstellen Sie ein neues Verzeichnis für unsere Projektdateien:
mkdir -p ~/project/http_status_lab
cd ~/project/http_status_lab
  1. Erstellen Sie mit der WebIDE eine neue Datei namens test_request.py im Verzeichnis http_status_lab mit 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}")
  1. 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:

  1. Testen Sie eine erfolgreiche Anfrage (200 OK):
python status_code_tester.py 200

Erwartete Ausgabe:

Status Code: 200
Response OK: True
  1. Testen Sie einen Client-Fehler (404 Not Found):
python status_code_tester.py 404

Erwartete Ausgabe:

Status Code: 404
Response OK: False
  1. 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:

  1. Benutzerdefinierte Ausnahmeklassen, die die Basisklasse Exception erweitern
  2. Hierarchische Ausnahmen für verschiedene Arten von Fehlern
  3. Detaillierte Protokollierung für Debugging und Überwachung
  4. 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:

  1. Erstellen einer wiederverwendbaren API-Client-Klasse
  2. Implementierung einer umfassenden Fehlerbehandlung
  3. Protokollierung von Anfragen und Antworten zum Debuggen
  4. Parsen verschiedener Antwortformate
  5. 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.