기술나눔

WSGI 서버 튜토리얼: `start_response` 메소드 분석

2024-07-12

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

Python WSGI 서버 튜토리얼:start_response 방법 분석

이 기사에서는 WSGI 서버를 자세히 분석합니다. start_response 방법.이 메소드는 HTTP 응답의 상태 코드와 응답 헤더를 처리하고write 응답 데이터를 보내는 데 사용되는 기능입니다. 이 메서드가 한 줄씩 작동하는 방식을 설명하고 해당 기능을 이해하는 데 도움이 되는 몇 가지 배경 지식을 제공합니다.

배경 지식

WSGI(Web Server Gateway Interface)는 웹 서버를 웹 애플리케이션이나 프레임워크와 연결하는 데 사용되는 표준 인터페이스입니다. WSGI를 통해 서버와 애플리케이션 간에 통신하고 HTTP 요청 및 응답을 처리할 수 있습니다.

WSGI 서버를 구현할 때,start_response 이 메소드는 WSGI 애플리케이션이 HTTP 응답 상태 및 응답 헤더를 설정하기 위해 호출하고 응답 데이터를 작성하기 위한 함수를 반환하는 핵심 부분입니다.

start_response 메소드 구현

다음은 전형적인 start_response 메소드 구현:

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

단계별 설명

  1. 다루다 exc_info 매개변수
if exc_info:
    try:
        if headers_sent:
            reraise(*exc_info)
    finally:
        exc_info = None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • exc_info 인수에는 일반적으로 다음 형식의 예외 튜플이 포함됩니다.(type, value, traceback) , 예외 처리에 사용됩니다.만약에exc_info 다음을 위한 것이 아닙니다None, 처리해야 할 예외가 있음을 나타냅니다.
  • try 블록 내 검사headers_sent 응답 헤더가 전송되었는지 여부입니다.응답 헤더가 전송된 경우 다음을 호출하세요.reraise(*exc_info) 예외를 다시 발생시킵니다.
  • finally 블록은 예외를 처리한 후exc_info 로 설정None처리의 중복을 피하기 위해.
  1. 응답 헤더가 설정되었는지 확인하세요.
elif headers_set:
    raise AssertionError("Headers already set")
  • 1
  • 2
  • 만약에 headers_set 목록에는 이미 값이 포함되어 있습니다(즉, 응답 헤더가 설정됨).AssertionError 이상.이 점검은 다음을 보장합니다.start_response 응답 헤더를 설정하기 위해 한 번만 호출할 수 있습니다.
  1. 응답 상태 및 응답 헤더 설정
headers_set[:] = [status, response_headers]
  • 1
  • 슬라이스 할당을 사용하여 status 그리고response_headers 할당headers_set 목록.이것의 목적은 유지하는 것입니다.headers_set 참조하지만 내용을 업데이트합니다.
  • status 예를 들어 HTTP 응답 상태 코드 및 메시지를 나타내는 문자열입니다."200 OK"
  • response_headers 튜플을 포함하는 목록입니다. 각 튜플은 응답 헤더의 키-값 쌍을 나타냅니다. 예를 들어[("Content-Type", "text/html"), ("Content-Length", "123")]
  1. 반품 write 기능
return write
  • 1
  • start_response 이 메서드는write 기능. 이 함수는 응답 데이터를 보내기 위해 WSGI 애플리케이션에서 호출됩니다.

사용예

다음은 사용 방법을 보여주는 완전한 예입니다. start_response 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

요약하다

이 튜토리얼을 통해 WSGI 서버를 자세히 분석했습니다. start_response HTTP 응답의 상태 코드와 응답 헤더를 처리하는 방법을 설명하고 응답 데이터를 쓰기 위한 함수를 반환하는 메서드입니다. 이러한 내용을 이해하면 WSGI 사양을 더 잘 이해하고 맞춤형 WSGI 서버를 구현하는 데 도움이 됩니다. 이 튜토리얼이 도움이 되기를 바랍니다.자세한 내용과 예시는 참고하세요공식 문서