Partage de technologie

Tutoriel du serveur WSGI : analyse de la méthode `start_response`

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Tutoriel du serveur Python WSGI :start_response Analyse de la méthode

Dans cet article, nous analyserons en détail un serveur WSGI start_response méthode.Cette méthode est chargée de traiter le code d'état et les en-têtes de réponse de la réponse HTTP et de renvoyer unwrite Fonction utilisée pour envoyer des données de réponse. Nous expliquerons le fonctionnement de la méthode ligne par ligne et fournirons quelques informations générales pour vous aider à comprendre ses capacités.

connaissances de base

WSGI (Web Server Gateway Interface) est une interface standard utilisée pour connecter un serveur Web à une application ou un framework Web. Grâce à WSGI, vous pouvez communiquer entre le serveur et l'application et gérer les requêtes et réponses HTTP.

Lors de la mise en œuvre d'un serveur WSGI,start_response La méthode est un élément clé appelé par l'application WSGI pour définir l'état de la réponse HTTP et les en-têtes de réponse, et renvoie une fonction pour écrire les données de réponse.

start_response Implémentation de la méthode

Ce qui suit est un exemple typique start_response Mise en œuvre de la méthode :

def start_response(status, response_headers, exc_info=None):
    if exc_info:
        try:
            if headers_sent:
                reraise(*exc_info)
        finally:
            exc_info = None
    elif headers_set:
        raise AssertionError("Headers already set")
    headers_set[:] = [status, response_headers]
    return write
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Explication étape par étape

  1. traiter avec exc_info paramètre
if exc_info:
    try:
        if headers_sent:
            reraise(*exc_info)
    finally:
        exc_info = None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • exc_info L'argument contient généralement un tuple d'exception au format(type, value, traceback) , utilisé pour la gestion des exceptions.siexc_info Pas pourNone, indiquant qu'il existe une exception qui doit être gérée.
  • try Contrôles en blocheaders_sent Si l'en-tête de réponse a été envoyé.Si les en-têtes de réponse ont été envoyés, appelezreraise(*exc_info) Renvoyez l'exception.
  • finally block garantit qu'après avoir traité l'exception, leexc_info mis àNonepour éviter la duplication du traitement.
  1. Vérifiez si l'en-tête de réponse a été défini
elif headers_set:
    raise AssertionError("Headers already set")
  • 1
  • 2
  • si headers_set La liste contient déjà des valeurs (c'est-à-dire que l'en-tête de réponse a été défini), soulèveAssertionError anormal.Ce contrôle garantitstart_response Ne peut être appelé qu’une seule fois pour définir les en-têtes de réponse.
  1. Définir le statut de la réponse et les en-têtes de réponse
headers_set[:] = [status, response_headers]
  • 1
  • Utilisez l'affectation de tranche pour status etresponse_headers assigné àheaders_set liste.Le but est de retenirheaders_set référence, mais met à jour son contenu.
  • status est une chaîne représentant le code d'état et le message de la réponse HTTP, par exemple"200 OK"
  • response_headers est une liste contenant des tuples, chaque tuple représente une paire clé-valeur d'un en-tête de réponse, par exemple[("Content-Type", "text/html"), ("Content-Length", "123")]
  1. retour write fonction
return write
  • 1
  • start_response La méthode renvoie unwrite fonction. Cette fonction est appelée par l'application WSGI pour envoyer des données de réponse.

Exemple d'utilisation

Voici un exemple complet montrant comment utiliser start_response Méthodes pour gérer les réponses WSGI :

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.headers_set = []
        self.headers_sent = []

        def start_response(status, response_headers, exc_info=None):
            if exc_info:
                try:
                    if self.headers_sent:
                        raise exc_info[1]
                finally:
                    exc_info = None
            elif self.headers_set:
                raise AssertionError("Headers already set")
            self.headers_set[:] = [status, response_headers]
            return self.write

        def write(data):
            assert self.headers_set, "write() before start_response"
            if not self.headers_sent:
                status, response_headers = self.headers_sent[:] = self.headers_set
                try:
                    code, msg = status.split(None, 1)
                except ValueError:
                    code, msg = status, ""
                code = int(code)
                self.send_response(code, msg)
                header_keys = set()
                for key, value in response_headers:
                    self.send_header(key, value)
                    key = key.lower()
                    header_keys.add(key)
                if not (
                    "content-length" in header_keys
                    or self.environ["REQUEST_METHOD"] == "HEAD"
                    or code < 200
                    or code in (204, 304)
                ):
                    self.close_connection = True
                    self.send_header("Connection", "close")
                if "server" not in header_keys:
                    self.send_header("Server", self.version_string())
                if "date" not in header_keys:
                    self.send_header("Date", self.date_time_string())
                self.end_headers()

            assert isinstance(data, bytes), "applications must write bytes"
            self.wfile.write(data)
            self.wfile.flush()

        self.write = write
        self.environ = self.make_environ()

        try:
            result = self.server.app(self.environ, start_response)
            try:
                for data in result:
                    write(data)
                if not self.headers_sent:
                    write(b"")
            finally:
                if hasattr(result, "close"):
                    result.close()
        except Exception as e:
            self.send_error(500, str(e))

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        print("Server started at {}:{}".format(HOST, PORT))
        server.serve_forever()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

Résumer

A travers ce tutoriel, nous avons analysé en détail un serveur WSGI start_response Méthode qui explique comment elle gère le code d'état et les en-têtes de réponse d'une réponse HTTP, et renvoie une fonction pour écrire les données de réponse. Comprendre ces contenus vous aidera à mieux comprendre la spécification WSGI et à implémenter un serveur WSGI personnalisé. J'espère que ce tutoriel vous sera utile.Pour plus de détails et d'exemples, veuillez vous référer àDocumentation officielle