wsgiref — WSGI 유틸리티와 참조 구현
wsgiref — WSGI 유틸리티와 참조 구현
wsgiref는 WSGI 명세의 참조 구현(reference implementation)으로, 웹 서버나 프레임워크에 WSGI 지원을 추가하는 데 쓸 수 있어요. WSGI 환경 변수·응답 헤더를 다루는 유틸리티, WSGI 서버 구현용 기본 클래스, WSGI 애플리케이션을 서빙하는 데모 HTTP 서버, 정적 타입 검사용 타입, 그리고 WSGI 서버·애플리케이션이 WSGI 명세(PEP 3333)에 부합하는지 검사하는 검증 도구를 제공합니다.
출처: Python 표준 라이브러리
경고 —
wsgiref는 참조 구현이라 프로덕션용으로 권장되지 않습니다. 이 모듈은 기본적인 보안 검사만 구현해요.
본문
웹 서버 게이트웨이 인터페이스(WSGI, Web Server Gateway Interface)는 웹 서버 소프트웨어와 Python으로 작성된 웹 애플리케이션 사이의 표준 인터페이스입니다. 표준 인터페이스가 있으면 WSGI를 지원하는 애플리케이션을 다양한 웹 서버에서 쉽게 쓸 수 있어요.
WSGI 설계의 모든 세부 사항과 경계 사례를 알아야 하는 사람은 웹 서버와 프로그래밍 프레임워크 저자뿐입니다. WSGI 애플리케이션을 설치하거나 기존 프레임워크로 웹 애플리케이션을 작성하는 데 WSGI의 모든 세부 사항을 이해할 필요는 없어요.
wsgiref는 웹 서버나 프레임워크에 WSGI 지원을 추가하는 데 쓸 수 있는 WSGI 명세의 참조 구현입니다. WSGI에 대한 더 자세한 정보와 튜토리얼·다른 리소스 링크는 wsgi.readthedocs.io를 참고하세요.
wsgiref.util — WSGI 환경 유틸리티
이 모듈은 WSGI 환경을 다루는 다양한 유틸리티 함수를 제공합니다. WSGI 환경은 PEP 3333에 설명된 HTTP 요청 변수를 담는 딕셔너리예요. environ 매개변수를 받는 모든 함수는 WSGI 호환 딕셔너리가 제공되기를 기대합니다. 자세한 명세는 PEP 3333, 타입 어노테이션에 쓸 수 있는 타입 별칭은 WSGIEnvironment를 참고하세요.
wsgiref.util.guess_scheme(environ)
environ 딕셔너리에서 HTTPS 환경 변수를 확인해 wsgi.url_scheme이 "http"인지 "https"인지 추측해 문자열을 반환합니다.
이 함수는 CGI나 FastCGI 같은 CGI류 프로토콜을 감싸는 게이트웨이를 만들 때 유용해요. 보통 그런 프로토콜을 제공하는 서버는 SSL로 요청을 받으면 값이 "1", "yes", "on"인 HTTPS 변수를 포함합니다. 그래서 이 함수는 그런 값을 찾으면 "https", 아니면 "http"를 반환합니다.
wsgiref.util.request_uri(environ, include_query=True)
PEP 3333의 "URL Reconstruction" 절에 있는 알고리즘을 사용해 전체 요청 URI를 반환하며, 선택적으로 쿼리 문자열을 포함합니다. include_query가 거짓이면 결과 URI에 쿼리 문자열이 포함되지 않습니다.
wsgiref.util.application_uri(environ)
request_uri()와 비슷하지만 PATH_INFO와 QUERY_STRING 변수를 무시합니다. 결과는 요청이 가리키는 애플리케이션 객체의 기본 URI입니다.
wsgiref.util.shift_path_info(environ)
PATH_INFO에서 이름 하나를 SCRIPT_NAME으로 옮기고 그 이름을 반환합니다. environ 딕셔너리가 제자리에서 수정되므로, 원래 PATH_INFO나 SCRIPT_NAME을 보존해야 한다면 복사본을 쓰세요.
PATH_INFO에 남은 경로 세그먼트가 없으면 None을 반환합니다.
보통 이 루틴은 요청 URI 경로의 각 부분을 처리하는 데 씁니다. 예를 들어 경로를 일련의 딕셔너리 키로 취급하는 경우죠. 이 루틴은 대상 URI에 위치한 다른 WSGI 애플리케이션을 호출하기에 적합하게 넘겨받은 환경을 수정합니다. 예를 들어 /foo에 WSGI 애플리케이션이 있고 요청 URI 경로가 /foo/bar/baz이며 /foo의 WSGI 애플리케이션이 shift_path_info()를 호출하면 문자열 "bar"를 받고, 환경은 /foo/bar의 WSGI 애플리케이션에 넘기기 적합하게 갱신됩니다. 즉 SCRIPT_NAME은 /foo에서 /foo/bar로, PATH_INFO는 /bar/baz에서 /baz로 바뀝니다.
PATH_INFO가 그냥 "/"일 때 보통 빈 경로 세그먼트는 무시되고 SCRIPT_NAME은 보통 슬래시로 끝나지 않지만, 이 루틴은 빈 문자열을 반환하고 SCRIPT_NAME에 트레일링 슬래시를 추가합니다. 이는 의도된 동작으로, 이 루틴으로 객체 순회를 할 때 /x로 끝나는 URI와 /x/로 끝나는 URI를 애플리케이션이 구분할 수 있게 하기 위해서예요.
wsgiref.util.setup_testing_defaults(environ)
테스트 목적으로 사소한 기본값으로 environ을 갱신합니다. 이 루틴은 HTTP_HOST, SERVER_NAME, SERVER_PORT, REQUEST_METHOD, SCRIPT_NAME, PATH_INFO, 그리고 PEP 3333이 정의한 모든 wsgi.* 변수를 포함해 WSGI에 필요한 다양한 매개변수를 추가해요. 기본값만 제공하며 이 변수들의 기존 설정을 대체하지는 않습니다.
이 루틴은 WSGI 서버·애플리케이션의 단위 테스트가 더미 환경을 쉽게 설정하도록 하기 위한 것입니다. 데이터가 가짜이므로 실제 WSGI 서버나 애플리케이션에서는 쓰면 안 돼요.
예시 사용:
from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server
# A relatively simple WSGI application. It's going to print out the
# environment dictionary after being updated by setup_testing_defaults
def simple_app(environ, start_response):
setup_testing_defaults(environ)
status = '200 OK'
headers = [('Content-type', 'text/plain; charset=utf-8')]
start_response(status, headers)
ret = [("%s: %s\n" % (key, value)).encode("utf-8")
for key, value in environ.items()]
return ret
with make_server('', 8000, simple_app) as httpd:
print("Serving on port 8000...")
httpd.serve_forever()
위 환경 함수들에 더해 wsgiref.util 모듈은 다음 잡다한 유틸리티도 제공합니다.
wsgiref.util.is_hop_by_hop(header_name)
header_name이 RFC 2616이 정의한 HTTP/1.1 "Hop-by-Hop" 헤더이면 True를 반환합니다.
class wsgiref.util.FileWrapper(filelike, blksize=8192)
파일류 객체를 이터레이터로 변환하는 데 쓰는 wsgiref.types.FileWrapper 프로토콜의 구체적 구현입니다. 결과 객체는 반복 가능하며, 객체를 반복하는 동안 선택 blksize 매개변수가 filelike 객체의 read() 메서드에 반복적으로 전달되어 yield할 바이트열을 얻어요. read()가 빈 바이트열을 반환하면 반복이 끝나고 재개할 수 없습니다.
filelike에 close() 메서드가 있으면 반환된 객체에도 close() 메서드가 있고, 호출 시 filelike 객체의 close() 메서드를 호출해요.
예시 사용:
from io import StringIO
from wsgiref.util import FileWrapper
# We're using a StringIO-buffer for as the file-like object
filelike = StringIO("This is an example file-like object"*10)
wrapper = FileWrapper(filelike, blksize=5)
for chunk in wrapper:
print(chunk)
버전 3.11에서 변경:
__getitem__()메서드 지원이 제거되었습니다.
wsgiref.headers — WSGI 응답 헤더 도구
이 모듈은 매핑류 인터페이스로 WSGI 응답 헤더를 편리하게 다루는 단일 클래스 Headers를 제공합니다.
class wsgiref.headers.Headers([headers])
PEP 3333에 설명된 헤더 이름/값 튜플의 목록인 headers를 감싸는 매핑류 객체를 만듭니다. headers의 기본값은 빈 목록이에요. Headers 객체는 __getitem__(), get(), __setitem__(), setdefault(), __delitem__(), __contains__()를 포함한 일반적인 매핑 연산을 지원합니다. 각 메서드에서 키는 헤더 이름(대소문자 무시)이고 값은 그 헤더 이름과 연결된 첫 값입니다. 헤더를 설정하면 그 헤더의 기존 값을 모두 삭제한 뒤 감싼 헤더 목록 끝에 새 값을 추가합니다. Headers의 기존 순서는 일반적으로 유지되며, 새 헤더는 감싼 목록 끝에 추가됩니다.
딕셔너리와 달리 Headers 객체는 감싼 헤더 목록에 없는 키를 얻거나 삭제하려 해도 오류를 일으키지 않아요. 존재하지 않는 헤더를 얻으면 그냥 None을 반환하고, 존재하지 않는 헤더를 삭제해도 아무 일도 없습니다.
Headers 객체는 keys(), values(), items() 메서드도 지원합니다. keys()와 items()가 반환한 목록은 다중 값 헤더가 있으면 같은 키를 여러 번 포함할 수 있어요. Headers 객체의 len()은 items()의 길이와 같으며, 이는 감싼 헤더 목록의 길이와 같습니다. 실제로 items() 메서드는 감싼 헤더 목록의 복사본만 반환합니다.
Headers 객체에 bytes()를 호출하면 HTTP 응답 헤더로 전송하기 적합한 형식의 바이트열을 반환합니다. 각 헤더는 콜론과 공백으로 구분된 값과 함께 한 줄에 놓이며, 각 줄은 캐리지 리턴과 줄 바꿈으로 끝나고 바이트열은 빈 줄로 끝나요.
매핑 인터페이스와 형식화 기능에 더해 Headers 객체는 다중 값 헤더를 조회·추가하고 MIME 매개변수를 가진 헤더를 추가하는 다음 메서드도 가집니다.
get_all(name)
명명된 헤더의 모든 값 목록을 반환합니다. 반환된 목록은 원래 헤더 목록에 나타난 순서나 이 인스턴스에 추가된 순서로 정렬되며 중복을 포함할 수 있어요. 삭제 후 다시 삽입된 필드는 항상 헤더 목록에 추가됩니다. 주어진 이름의 필드가 없으면 빈 목록을 반환합니다.
add_header(name, value, **_params)
선택적 MIME 매개변수를 키워드 인자로 지정해 (가능하면 다중 값인) 헤더를 추가합니다. name은 추가할 헤더 필드이고, 키워드 인자로 헤더 필드의 MIME 매개변수를 설정할 수 있어요. 각 매개변수는 문자열 또는 None이어야 합니다. 대시는 Python 식별자에 불법이지만 많은 MIME 매개변수 이름이 대시를 포함하므로, 매개변수 이름의 밑줄은 대시로 변환됩니다. 매개변수 값이 문자열이면 name="value" 형태로 헤더 값 매개변수에 추가되고, None이면 매개변수 이름만 추가됩니다. (값이 없는 MIME 매개변수에 쓰입니다.) 예시 사용:
h.add_header('content-disposition', 'attachment', filename='bud.gif')
위 코드는 다음과 같은 헤더를 추가합니다.
Content-Disposition: attachment; filename="bud.gif"
버전 3.5에서 변경:
headers매개변수가 선택적입니다.
wsgiref.simple_server — 간단한 WSGI HTTP 서버
이 모듈은 WSGI 애플리케이션을 서빙하는 간단한 HTTP 서버(http.server 기반)를 구현합니다. 각 서버 인스턴스는 주어진 호스트와 포트에서 단일 WSGI 애플리케이션을 서빙해요. 단일 호스트·포트에서 여러 애플리케이션을 서빙하려면, 각 요청에 대해 어떤 애플리케이션을 호출할지 고르도록 PATH_INFO를 파싱하는 WSGI 애플리케이션을 만들어야 합니다. (예: wsgiref.util의 shift_path_info() 함수 사용)
wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)
host와 port에서 요청을 듣고 app에 대한 연결을 받아들이는 새 WSGI 서버를 만듭니다. 반환 값은 제공된 server_class의 인스턴스이며, 지정된 handler_class로 요청을 처리합니다. app은 PEP 3333이 정의한 WSGI 애플리케이션 객체여야 해요.
예시 사용:
from wsgiref.simple_server import make_server, demo_app
with make_server('', 8000, demo_app) as httpd:
print("Serving HTTP on port 8000...")
# Respond to requests until process is killed
httpd.serve_forever()
# Alternative: serve one request, then exit
httpd.handle_request()
wsgiref.simple_server.demo_app(environ, start_response)
이 함수는 작지만 완전한 WSGI 애플리케이션으로, "Hello world!" 메시지와 environ 매개변수에 제공된 key/value 쌍의 목록을 담은 텍스트 페이지를 반환합니다. WSGI 서버(예: wsgiref.simple_server)가 간단한 WSGI 애플리케이션을 올바르게 실행하는지 확인하는 데 유용해요. start_response callable은 StartResponse 프로토콜을 따라야 합니다.
class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)
WSGIServer 인스턴스를 만듭니다. server_address는 (host, port) 튜플이어야 하고, RequestHandlerClass는 요청을 처리하는 데 사용될 http.server.BaseHTTPRequestHandler의 하위 클래스여야 합니다. 보통 이 생성자를 직접 호출할 필요는 없어요. make_server() 함수가 모든 세부 사항을 처리해 주니까요.
WSGIServer는 http.server.HTTPServer의 하위 클래스이므로 serve_forever()와 handle_request() 같은 모든 메서드를 쓸 수 있습니다. WSGIServer는 WSGI 특유의 다음 메서드도 제공합니다.
set_app(application)— 호출 가능 애플리케이션을 요청을 받을 WSGI 애플리케이션으로 설정합니다.get_app()— 현재 설정된 애플리케이션 callable을 반환합니다.
그러나 보통 이 추가 메서드를 쓸 필요는 없습니다. set_app()은 보통 make_server()가 호출하고, get_app()은 주로 요청 핸들러 인스턴스를 위해 존재하니까요.
class wsgiref.simple_server.WSGIRequestHandler(request, client_address, server)
주어진 요청(즉 소켓), client_address((host, port) 튜플), server(WSGIServer 인스턴스)에 대한 HTTP 핸들러를 만듭니다. 이 클래스의 인스턴스를 직접 만들 필요는 없어요. WSGIServer 객체가 필요할 때 자동으로 만듭니다. 그러나 이 클래스를 하위 클래스화해 make_server() 함수의 handler_class로 제공할 수는 있습니다. 하위 클래스에서 오버라이드할 관련 메서드 몇 가지:
get_environ()— 요청에 대한WSGIEnvironment딕셔너리를 반환합니다. 기본 구현은WSGIServer객체의base_environ딕셔너리 속성의 내용을 복사한 뒤 HTTP 요청에서 파생된 다양한 헤더를 추가합니다. 이 메서드를 호출할 때마다 PEP 3333에 명시된 관련 CGI 환경 변수를 모두 담은 새 딕셔너리를 반환해야 해요.get_stderr()—wsgi.errors스트림으로 사용할 객체를 반환합니다. 기본 구현은 그냥sys.stderr를 반환합니다.handle()— HTTP 요청을 처리합니다. 기본 구현은wsgiref.handlers클래스를 사용해 실제 WSGI 애플리케이션 인터페이스를 구현하는 핸들러 인스턴스를 만듭니다.
wsgiref.validate — WSGI 적합성 검사기
새 WSGI 애플리케이션 객체, 프레임워크, 서버, 미들웨어를 만들 때 wsgiref.validate로 새 코드의 적합성을 검증하는 것이 유용할 수 있어요. 이 모듈은 WSGI 서버나 게이트웨이와 WSGI 애플리케이션 객체 사이의 통신을 검증하는 WSGI 애플리케이션 객체를 만들어 양쪽 다 프로토콜 적합성을 검사하는 함수를 제공합니다.
이 유틸리티가 완전한 PEP 3333 준수를 보장하지는 않는다는 점을 알아 두세요. 이 모듈에서 오류가 없다고 해서 오류가 존재하지 않는다는 뜻은 아닙니다. 그러나 이 모듈이 오류를 만들면, 서버나 애플리케이션 중 하나가 100% 준수하지 않는 것은 거의 확실합니다.
이 모듈은 Ian Bicking의 "Python Paste" 라이브러리에서 가져온 paste.lint 모듈을 기반으로 합니다.
wsgiref.validate.validator(application)
application을 감싸고 새 WSGI 애플리케이션 객체를 반환합니다. 반환된 애플리케이션은 모든 요청을 원래 애플리케이션으로 전달하고, 애플리케이션과 그것을 호출하는 서버 모두가 WSGI 명세와 RFC 2616에 적합한지 검사합니다.
감지된 부적합은 AssertionError를 발생시키지만, 이러한 오류가 어떻게 처리될지는 서버에 따라 달라집니다. 예를 들어 wsgiref.simple_server와 wsgiref.handlers 기반의 다른 서버(오류 처리 메서드를 다른 일로 오버라이드하지 않은)는 오류가 발생했다는 메시지를 출력하고 sys.stderr 또는 다른 오류 스트림에 traceback을 덤프할 뿐입니다.
이 래퍼는 warnings 모듈을 사용해 의심스럽지만 PEP 3333이 실제로 금지하지 않을 수 있는 동작을 나타내는 출력도 만들 수 있습니다. Python 명령줄 옵션이나 warnings API로 억제하지 않으면 그런 경고는 sys.stderr에 기록됩니다 (wsgi.errors가 같은 객체가 아닌 한).
예시 사용:
from wsgiref.validate import validator
from wsgiref.simple_server import make_server
# Our callable object which is intentionally not compliant to the
# standard, so the validator is going to break
def simple_app(environ, start_response):
status = '200 OK' # HTTP Status
headers = [('Content-type', 'text/plain')] # HTTP Headers
start_response(status, headers)
# This is going to break because we need to return a list, and
# the validator is going to inform us
return b"Hello World"
# This is the application wrapped in a validator
validator_app = validator(simple_app)
with make_server('', 8000, validator_app) as httpd:
print("Listening on port 8000....")
httpd.serve_forever()
wsgiref.handlers — 서버/게이트웨이 기본 클래스
이 모듈은 WSGI 서버와 게이트웨이를 구현하기 위한 기본 핸들러 클래스를 제공합니다. 이 기본 클래스들은 CGI류 환경과 입력·출력·오류 스트림만 주어지면 WSGI 애플리케이션과 통신하는 작업 대부분을 처리해요.
class wsgiref.handlers.CGIHandler
sys.stdin, sys.stdout, sys.stderr, os.environ을 통한 CGI 기반 호출입니다. WSGI 애플리케이션이 있고 그것을 CGI 스크립트로 실행하려 할 때 유용해요. CGIHandler().run(app)을 호출하기만 하면 됩니다. app은 호출하려는 WSGI 애플리케이션 객체예요. 이 클래스는 wsgi.run_once를 true, wsgi.multithread를 false, wsgi.multiprocess를 true로 설정하고 필요한 CGI 스트림과 환경을 얻기 위해 항상 sys와 os를 사용하는 BaseCGIHandler의 하위 클래스입니다.
class wsgiref.handlers.IISCGIHandler
Microsoft IIS 웹 서버에, config 옵션 allowPathInfo(IIS>=7)나 metabase 옵션 allowPathInfoForScriptMappings(IIS<7)을 설정하지 않고 배포할 때 쓰는, CGIHandler의 특수 대안입니다. 기본적으로 IIS는 앞에 SCRIPT_NAME을 중복한 PATH_INFO를 주므로, 라우팅을 구현하려는 WSGI 애플리케이션에 문제가 됩니다. 이 핸들러는 그런 중복 경로를 제거합니다.
IIS는 올바른 PATH_INFO를 넘기도록 구성될 수 있지만, 그러면 PATH_TRANSLATED가 틀려지는 다른 버그가 생겨요. 다행히 이 변수는 거의 쓰이지 않고 WSGI가 보장하지도 않습니다. 그러나 IIS<7에서는 설정을 vhost 수준에서만 할 수 있어 다른 모든 스크립트 매핑에 영향을 주며, 그 중 많은 것이 PATH_TRANSLATED 버그에 노출되면 깨집니다. 이 때문에 IIS<7은 거의 항상 이 수정 없이 배포됩니다 (IIS7도 이에 대한 UI가 아직 없어 거의 쓰지 않습니다).
CGI 코드가 그 옵션이 설정됐는지 알 방법이 없으므로 별도의 핸들러 클래스가 제공됩니다. CGIHandler와 같은 방식, 즉 IISCGIHandler().run(app)을 호출해 쓰며 app은 호출하려는 WSGI 애플리케이션 객체입니다. (버전 3.2에서 추가)
class wsgiref.handlers.BaseCGIHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)
CGIHandler와 비슷하지만 sys·os 모듈 대신 CGI 환경과 I/O 스트림을 명시적으로 지정합니다. multithread와 multiprocess 값은 핸들러 인스턴스가 실행하는 모든 애플리케이션의 wsgi.multithread·wsgi.multiprocess 플래그를 설정하는 데 사용됩니다.
이 클래스는 HTTP "origin server"가 아닌 소프트웨어용으로 설계된 SimpleHandler의 하위 클래스입니다. Status: 헤더로 HTTP 상태를 보내는 게이트웨이 프로토콜 구현(CGI, FastCGI, SCGI 등)을 작성 중이라면 SimpleHandler 대신 이 클래스를 하위 클래스화하고 싶을 거예요.
class wsgiref.handlers.SimpleHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)
BaseCGIHandler와 비슷하지만 HTTP origin server용으로 설계되었습니다. HTTP 서버 구현을 작성 중이라면 BaseCGIHandler 대신 이 클래스를 하위 클래스화하고 싶을 거예요.
이 클래스는 BaseHandler의 하위 클래스이며, 생성자를 통해 환경과 스트림을 명시적으로 설정하도록 __init__(), get_stdin(), get_stderr(), add_cgi_vars(), _write(), _flush() 메서드를 오버라이드합니다. 제공된 환경과 스트림은 stdin, stdout, stderr, environ 속성에 저장됩니다. stdout의 write() 메서드는 io.BufferedIOBase처럼 각 청크를 완전히 써야 해요.
class wsgiref.handlers.BaseHandler
WSGI 애플리케이션을 실행하기 위한 추상 기본 클래스입니다. 각 인스턴스는 단일 HTTP 요청을 처리하지만, 원칙적으로 여러 요청에 재사용 가능한 하위 클래스를 만들 수도 있습니다.
BaseHandler 인스턴스는 외부에서 쓰기 위한 메서드가 하나뿐입니다.
run(app)
지정한 WSGI 애플리케이션 app을 실행합니다. 다른 모든 BaseHandler 메서드는 애플리케이션을 실행하는 과정에서 이 메서드가 호출하므로, 주로 프로세스를 커스터마이즈하기 위해 존재합니다.
하위 클래스에서 반드시 오버라이드해야 하는 메서드는 다음과 같습니다.
_write(data)— 클라이언트로 전송할 데이터를 버퍼링합니다. 이 메서드가 실제로 데이터를 전송해도 괜찮아요.BaseHandler는 기본 시스템이 쓰기와 플러시를 실제로 구분할 때 더 큰 효율을 위해 쓰기와 플러시 연산을 분리할 뿐입니다._flush()— 버퍼링된 데이터를 클라이언트로 전송하도록 강제합니다. 이 메서드가 no-op이어도 괜찮습니다 (즉_write()가 실제로 데이터를 보내는 경우).get_stdin()— 현재 처리 중인 요청의wsgi.input으로 쓰기 적합한InputStream호환 객체를 반환합니다.get_stderr()— 현재 처리 중인 요청의wsgi.errors로 쓰기 적합한ErrorStream호환 객체를 반환합니다.add_cgi_vars()— 현재 요청에 대한 CGI 변수를environ속성에 삽입합니다.
다음은 오버라이드할 수 있는 다른 메서드와 속성입니다. 이 목록은 요약일 뿐이며 오버라이드할 수 있는 모든 메서드를 포함하지는 않아요. 커스터마이즈한 BaseHandler 하위 클래스를 만들기 전에 추가 정보는 docstring과 소스 코드를 확인하세요.
WSGI 환경을 커스터마이즈하는 속성·메서드:
wsgi_multithread—wsgi.multithread환경 변수에 쓸 값.BaseHandler에서 기본적으로 true지만 다른 하위 클래스에서는 다른 기본값을 가지거나 생성자가 설정할 수 있어요.wsgi_multiprocess—wsgi.multiprocess환경 변수에 쓸 값. 기본적으로BaseHandler에서 true지만 다른 기본값을 가지거나 생성자가 설정할 수 있습니다.wsgi_run_once—wsgi.run_once환경 변수에 쓸 값.BaseHandler에서 기본적으로 false지만CGIHandler는 기본적으로 true로 설정해요.os_environ— 모든 요청의 WSGI 환경에 포함할 기본 환경 변수. 기본적으로wsgiref.handlers가 import될 때os.environ의 복사본이지만, 하위 클래스가 클래스 또는 인스턴스 수준에서 자신의 것을 만들 수 있어요. 기본값이 여러 클래스와 인스턴스 사이에 공유되므로 딕셔너리는 읽기 전용으로 간주해야 합니다.server_software—origin_server속성이 설정돼 있으면 이 속성의 값이 기본SERVER_SOFTWAREWSGI 환경 변수를, 그리고 HTTP 응답의 기본Server:헤더를 설정하는 데 사용됩니다. HTTP origin server가 아닌 핸들러(BaseCGIHandler,CGIHandler등)에서는 무시됩니다. (버전 3.3에서 변경: "Python"이라는 용어가 "CPython", "Jython" 같은 구현 특정 용어로 대체됨)get_scheme()— 현재 요청에 사용되는 URL 스킴을 반환합니다. 기본 구현은 현재 요청의environ변수를 기반으로 스킴이 "http"인지 "https"인지 추측하기 위해wsgiref.util의guess_scheme()함수를 사용합니다.setup_environ()—environ속성을 완전히 채워진 WSGI 환경으로 설정합니다. 기본 구현은 위의 모든 메서드·속성에 더해get_stdin(),get_stderr(),add_cgi_vars()메서드와wsgi_file_wrapper속성을 사용합니다. 또한origin_server속성이 참값이고server_software속성이 설정되어 있으면SERVER_SOFTWARE키가 없을 때 삽입합니다.
예외 처리를 커스터마이즈하는 메서드·속성:
log_exception(exc_info)— 서버 로그에exc_info튜플을 기록합니다.exc_info는(type, value, traceback)튜플이에요. 기본 구현은 요청의wsgi.errors스트림에 traceback을 쓰고 플러시할 뿐입니다. 하위 클래스는 이 메서드를 오버라이드해 형식을 바꾸거나 출력을 재지정하고, 관리자에게 traceback을 메일로 보내는 등 적절한 다른 동작을 할 수 있습니다.traceback_limit— 기본log_exception()메서드가 출력하는 traceback에 포함할 최대 프레임 수.None이면 모든 프레임을 포함합니다.error_output(environ, start_response)— 사용자를 위한 오류 페이지를 생성하는 WSGI 애플리케이션인 메서드. 클라이언트에 헤더를 보내기 전에 오류가 발생한 경우에만 호출됩니다. 이 메서드는sys.exception()으로 현재 오류에 접근할 수 있고,start_response를 호출할 때 그 정보를 전달해야 합니다 (PEP 3333의 "Error Handling" 절에 설명된 대로). 특히start_responsecallable은 StartResponse 프로토콜을 따라야 해요. 기본 구현은error_status,error_headers,error_body속성만 사용해 출력 페이지를 생성합니다. 하위 클래스는 더 동적인 오류 출력을 만들도록 오버라이드할 수 있습니다. 그러나 보안 관점에서 진단 정보를 아무 사용자에게나 내뱉는 것은 권장되지 않습니다. 이상적으로는 진단 출력을 활성화하려면 특별한 조치를 해야 하는데, 기본 구현이 아무것도 포함하지 않는 이유가 그거예요.error_status— 오류 응답에 사용하는 HTTP 상태. PEP 3333에 정의된 상태 문자열이어야 하며, 기본값은 500 코드와 메시지입니다.error_headers— 오류 응답에 사용하는 HTTP 헤더. PEP 3333에 설명된 WSGI 응답 헤더((name, value) 튜플) 목록이어야 합니다. 기본 목록은 content type을 text/plain으로 설정할 뿐이에요.error_body— 오류 응답 본문. HTTP 응답 본문 바이트열이어야 합니다. 기본값은 일반 텍스트 "A server error occurred. Please contact the administrator."입니다.
PEP 3333의 "선택적 플랫폼 특정 파일 처리" 기능을 위한 메서드·속성:
wsgi_file_wrapper—wsgiref.types.FileWrapper와 호환되는wsgi.file_wrapper팩토리 또는None. 이 속성의 기본값은wsgiref.util.FileWrapper클래스입니다.sendfile()— 플랫폼 특정 파일 전송을 구현하도록 오버라이드합니다. 이 메서드는 애플리케이션의 반환 값이wsgi_file_wrapper속성이 지정한 클래스의 인스턴스일 때만 호출됩니다. 파일 전송에 성공했으면 기본 전송 코드가 실행되지 않도록 참값을 반환해야 해요. 이 메서드의 기본 구현은 그냥 거짓 값을 반환합니다.
잡다한 메서드와 속성:
origin_server— 핸들러의_write()와_flush()가 HTTP 상태를 특별한Status:헤더에 원하는 CGI류 게이트웨이 프로토콜을 통하지 않고 클라이언트에 직접 통신하는 데 사용된다면 참값으로 설정해야 하는 속성입니다. 이 속성의 기본값은BaseHandler에서 true지만BaseCGIHandler와CGIHandler에서는 false예요.http_version—origin_server가 참이면 이 문자열 속성이 클라이언트에 설정된 응답의 HTTP 버전을 설정하는 데 사용됩니다. 기본값은"1.0"입니다.
wsgiref.handlers.read_environ()
CGI 변수를 os.environ에서 PEP 3333의 "bytes in unicode" 문자열로 트랜스코드해 새 딕셔너리를 반환합니다. 이 함수는 CGIHandler와 IISCGIHandler가 os.environ을 직접 사용하는 대신 씁니다. Python 3을 쓰는 모든 플랫폼·웹 서버에서 os.environ이 WSGI 호환인 것은 아니기 때문입니다. 특히 OS의 실제 환경이 Unicode(즉 Windows)이거나, 환경이 bytes인데 Python이 디코드에 사용하는 시스템 인코딩이 ISO-8859-1이 아닌 경우(즉 UTF-8을 쓰는 Unix 시스템)가 문제예요.
자신의 CGI 기반 핸들러를 구현한다면 os.environ에서 값을 그냥 복사하는 것보다 이 루틴을 쓸 가능성이 높아요. (버전 3.2에서 추가)
wsgiref.types — 정적 타입 검사용 WSGI 타입
이 모듈은 PEP 3333에 설명된 정적 타입 검사용 다양한 타입을 제공합니다. (버전 3.11에서 추가)
class wsgiref.types.StartResponse—start_response()callable(PEP 3333)을 설명하는typing.Protocol.wsgiref.types.WSGIEnvironment— WSGI 환경 딕셔너리를 설명하는 타입 별칭.wsgiref.types.WSGIApplication— WSGI 애플리케이션 callable을 설명하는 타입 별칭.class wsgiref.types.InputStream— WSGI 입력 스트림을 설명하는typing.Protocol.class wsgiref.types.ErrorStream— WSGI 오류 스트림을 설명하는typing.Protocol.class wsgiref.types.FileWrapper— 파일 래퍼를 설명하는typing.Protocol. 이 프로토콜의 구체적 구현은wsgiref.util.FileWrapper를 참고하세요.
예제 (Examples)
start_response callable이 StartResponse 프로토콜을 따라야 하는 작동하는 "Hello World" WSGI 애플리케이션입니다.
"""
Every WSGI application must have an application object - a callable
object that accepts two arguments. For that purpose, we're going to
use a function (note that you're not limited to a function, you can
use a class for example). The first argument passed to the function
is a dictionary containing CGI-style environment variables and the
second variable is the callable object.
"""
from wsgiref.simple_server import make_server
def hello_world_app(environ, start_response):
status = "200 OK" # HTTP Status
headers = [("Content-type", "text/plain; charset=utf-8")] # HTTP Headers
start_response(status, headers)
# The returned object is going to be printed
return [b"Hello World"]
with make_server("", 8000, hello_world_app) as httpd:
print("Serving on port 8000...")
# Serve until process is killed
httpd.serve_forever()
현재 디렉터리를 서빙하고, 명령줄에서 선택적 디렉터리와 포트 번호(기본: 8000)를 받는 WSGI 애플리케이션 예제입니다.
"""
Small wsgiref based web server. Takes a path to serve from and an
optional port number (defaults to 8000), then tries to serve files.
MIME types are guessed from the file names, 404 errors are raised
if the file is not found.
"""
import mimetypes
import os
import sys
from wsgiref import simple_server, util
def app(environ, respond):
# Get the file name and MIME type
fn = os.path.join(path, environ["PATH_INFO"][1:])
if "." not in fn.split(os.path.sep)[-1]:
fn = os.path.join(fn, "index.html")
mime_type = mimetypes.guess_file_type(fn)[0]
# Return 200 OK if file exists, otherwise 404 Not Found
if os.path.exists(fn):
respond("200 OK", [("Content-Type", mime_type)])
return util.FileWrapper(open(fn, "rb"))
else:
respond("404 Not Found", [("Content-Type", "text/plain")])
return [b"not found"]
if __name__ == "__main__":
# Get the path and port from command-line arguments
path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000
# Make and start the server until control-c
httpd = simple_server.make_server("", port, app)
print(f"Serving {path} on port {port}, control-C to stop")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("Shutting down.")
httpd.server_close()