Technologieaustausch

WSGI-Server-Tutorial: Methodenanalyse „start_response“.

2024-07-12

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

Tutorial zum Python-WSGI-Server:start_response Methodenanalyse

In diesem Artikel analysieren wir einen WSGI-Server im Detail start_response Methode.Diese Methode ist dafür verantwortlich, den Statuscode und die Antwortheader der HTTP-Antwort zu verarbeiten und eine zurückzugebenwrite Funktion zum Senden von Antwortdaten. Wir erklären Zeile für Zeile, wie die Methode funktioniert, und geben einige Hintergrundinformationen, um ihre Fähigkeiten zu verstehen.

Hintergrundwissen

WSGI (Web Server Gateway Interface) ist eine Standardschnittstelle, die zum Verbinden eines Webservers mit einer Webanwendung oder einem Framework verwendet wird. Über WSGI können Sie zwischen dem Server und der Anwendung kommunizieren und HTTP-Anfragen und -Antworten verarbeiten.

Bei der Implementierung eines WSGI-Serversstart_response Die Methode ist ein Schlüsselbestandteil, der von der WSGI-Anwendung aufgerufen wird, um den HTTP-Antwortstatus und die Antwortheader festzulegen, und eine Funktion zum Schreiben der Antwortdaten zurückgibt.

start_response Methodenimplementierung

Das Folgende ist ein typisches Beispiel start_response Methodenimplementierung:

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

Schritt-für-Schritt-Erklärung

  1. bewältigen exc_info Parameter
if exc_info:
    try:
        if headers_sent:
            reraise(*exc_info)
    finally:
        exc_info = None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • exc_info Das Argument enthält normalerweise ein Ausnahmetupel im Format(type, value, traceback) , wird für die Ausnahmebehandlung verwendet.Wennexc_info Nicht fürNone, was darauf hinweist, dass eine Ausnahme vorliegt, die behandelt werden muss.
  • try Blockinterne Kontrollenheaders_sent Ob der Antwortheader gesendet wurde.Wenn die Antwortheader gesendet wurden, rufen Sie anreraise(*exc_info) Die Ausnahme erneut auslösen.
  • finally Der Block stellt sicher, dass nach der Behandlung der Ausnahme dieexc_info einstellenNoneum eine Doppelverarbeitung zu vermeiden.
  1. Überprüfen Sie, ob der Antwortheader festgelegt wurde
elif headers_set:
    raise AssertionError("Headers already set")
  • 1
  • 2
  • Wenn headers_set Die Liste enthält bereits Werte (d. h. der Antwortheader wurde gesetzt), löst ausAssertionError abnormal.Diese Prüfung stellt sicherstart_response Kann nur einmal aufgerufen werden, um Antwortheader festzulegen.
  1. Legen Sie den Antwortstatus und die Antwortheader fest
headers_set[:] = [status, response_headers]
  • 1
  • Verwenden Sie die Slice-Zuweisung, um status Undresponse_headers Zugewiesen anheaders_set Liste.Der Zweck hiervon ist die Aufbewahrungheaders_set Verweis, aktualisiert aber seinen Inhalt.
  • status ist eine Zeichenfolge, die beispielsweise den Statuscode und die Nachricht der HTTP-Antwort darstellt"200 OK"
  • response_headers ist eine Liste mit Tupeln. Jedes Tupel stellt beispielsweise ein Schlüssel-Wert-Paar eines Antwortheaders dar[("Content-Type", "text/html"), ("Content-Length", "123")]
  1. zurückkehren write Funktion
return write
  • 1
  • start_response Die Methode gibt a zurückwrite Funktion. Diese Funktion wird von der WSGI-Anwendung aufgerufen, um Antwortdaten zu senden.

Anwendungsbeispiel

Hier ist ein vollständiges Beispiel, das die Verwendung zeigt start_response Methoden zur Verarbeitung von WSGI-Antworten:

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

Zusammenfassen

In diesem Tutorial haben wir einen WSGI-Server im Detail analysiert start_response Methode, die erklärt, wie sie mit dem Statuscode und den Antwortheadern einer HTTP-Antwort umgeht, und eine Funktion zum Schreiben der Antwortdaten zurückgibt. Das Verständnis dieser Inhalte wird Ihnen helfen, die WSGI-Spezifikation besser zu verstehen und einen angepassten WSGI-Server zu implementieren. Ich hoffe, dieses Tutorial ist hilfreich für Sie.Weitere Einzelheiten und Beispiele finden Sie unterOffizielle Dokumentation