정리 노트

wsgiref 모듈과 같이 WSGI 알아보기(Python) 본문

개념 정리

wsgiref 모듈과 같이 WSGI 알아보기(Python)

꿈만 꾸는 학부생 2022. 6. 25. 18:57
728x90

대학교 1학년 1학기 때 파이썬을 처음 배웠다. 가르쳐주신 여러 내용들 중 갑자기 WSGI라는 게 있었다는 게 기억나서 갑자기 여기서 끄적여본다. 이 글을 작성하는데 교수님의 강의 자료와 파이썬 documentation 홈페이지, 파이썬 3 바이블 책을 참고했다.

https://docs.python.org/ko/3/library/wsgiref.html

 

wsgiref — WSGI 유틸리티와 참조 구현 — Python 3.10.5 문서

wsgiref — WSGI 유틸리티와 참조 구현 WSGI(Web Server Gateway Interface)는 웹 서버 소프트웨어와 파이썬으로 작성된 웹 응용 프로그램 간의 표준 인터페이스입니다. 표준 인터페이스는 여러 웹 서버에서 W

docs.python.org

https://book.naver.com/bookdb/book_detail.naver?bid=7307934 

 

파이썬3 바이블

『파이썬3 바이블』은 파이썬에 대한 이해와 활용을 한 권으로 해결할 수 있는 책이다. 명료한 설명과 예제로 파이썬 3의 개념을 쉽게 다룬다. 실무에서 바로 적용할 수 있는 예제와 더불어, 자

book.naver.com

WSGI는 무엇인가?

WSGI는 웹 서버 소프트웨어와 파이썬으로 작성된 웹 응용 프로그램 간의 표준 인터레이스다. WSGI를 사용하면 여러 웹 서버와 프레임워크 사이에 이식성을 향상시킬 수 있다. 흔히 들어본 Django, Flask 등의 여러 응용 프레임워크가 WSGI에 기반해 개발돼있다.

WSGI는 확장이 가능하고 구현 방식과 관계없는 표준 인터페이스라 멀티 스레드와 멀티 프로세스 환경에서 작업할 수 있다.

코드로 보는 예시들

먼저 매우 간단하고 짧은 코드부터 보자.

from wsgiref.simple_server import make_server

def application(environ, start_response):    # 요청이 들어올 때 처리하는 코드
    start_response('200 OK', [('Content-Type', 'text/plain')])
    yield 'Hello World\n'    # 문자열을 응답의 몸체에 출력
    
httpd = make_server('localhost', 8051, application)    # IP와 Port number 지정

httpd.handle_request()    # 요청을 받기 시작

키워드 yield를 처음 본다. 뭔지 모르겠어서 찾아보니 이 사이트가 잘 설명해주고 있다. https://www.daleseo.com/python-yield/

wsgiref.simple_server 모듈은 WSGI 응용 프로그램을 제공하는 간단한 HTTP 서버를 구현한다. 각 서버의 인스턴스는 주어진 IP와 포트에서 단일 WSGI 응용 프로그램을 제공한다. make_server 함수를 통해 IP와 포트에서 수신을 기다리고 애플리케이션에 대한 연결을 수락하는 새 WSGI 서버를 만든다. 반환 값은 지정된 handler_class를 사용해 요청을 처리한다.

위 코드를 실행하면 아무 반응이 없다.

그럼 이 코드는 논리적으로 오류가 난 실패한 코드인가? 아니다. 위에서 좀 전에 설명했듯이 나는 간단한 '서버'를 구현한 것이다. 그러니 이를 확인하려면 Firefox나 Chrome 등의 인터넷 브라우저 창에서 'localhost:8051'에 접속해보자.

에러가 났다! wsgiref 모듈에서 handlers.py 안의 write 함수에서 에러가 발생한 것이라 해석된다. 해결 방법을 모르겠어서 바로 stackoverflow에 물어보니 에러의 원인과 해결책이 바로 나왔다.

Wsgi framework is built around Python 2.
Therefore, if there is stuff in your program that does not include Python 3 dependencies,
run the app with Python 2.
- Narayan Bhat

처음 알았다.. wsgi 프레임워크가 파이썬2 기반으로 만들어졌구나.. 파이썬 3에서 돌리려니 문제가 생겼구나! 예제 코드에서 파이썬 3에서만 돌아가는 코드는 없으므로 파이썬 2로 실행하니 정상적으로 작동되었다.

이번에는 문자열을 말고 좀 더 복잡한걸 화면에 띠워보자. 그럴려면 위 코드의 application 함수를 수정해야 한다.

def application(environ, start_response):    # environ: 환경 변수들을 담은 dictionary
    response_body = ['%s: %s' % (key, value) for key, value in sorted(environ.items())]
    response_body = '\n'.join(response_body)
    
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain'),
                        ('Content-Length', str(len(response_body)))]
    start_response(status, response_headers)
    return [response_body]

실행해보면 브라우저 창에 엄청나게 많은 내용들이 쏟아져 나온다. 이 내용들은 서버에게 보낸 요청에 있어서 여러 환경 변수 내용들이다. 저 내용들 전부 application 함수의 인자 'environ'에 들어있었던 거다.

이 코드에서 HTTP Method를 이용할 수도 있다. HTTP Method로 GET, POST, PUT, DELETE, HEAD 등이 있는데 여기서는 GET과 POST를 이용한 예시들을 보자. 이번에도 application 함수만 수정하고 이번에는 cgi 모듈에서 parse_qs를 가져온다.

GET 이용

from wsgiref.simple_server import make_server
from cgi import parse_qs

def_application(environ, start_response):
    d = parse_qs(environ['QUERY_STRING'])
    name = d.get('name', [''])[0]
    age = d.get('age', [''])[0]
    response_body = 'name: %s\nage: %s\n' % (name, age)
    
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain'),
    					('Content-Length', str(len(response_body)))]
    start_response(status, response_headers)
    return [response_body]
    
httpd = make_server('localhost', 8051, application)
httpd.serve_forever()

코드의 마지막 줄도 수정했는데, serve_forever 함수는 요청을 한 번이 아닌 계속 받아들일 수 있다. 쉬운 테스트를 위해 수정했다.

 

처음 코드를 돌리면 이름과 나이가 적혀있지 않는 화면이 보일 것이다.

주소창에 포트 넘버 옆에다 '/?name='아무 이름'&age='아무 숫자'를 추가해서 엔터를 치면 '아무 이름'과 '아무 숫자'가 화면에 출력된다.

POST 이용

POST를 이용하려면 application 함수의 초반만 수정하면 된다.

def application(environ, start_response):
    request_body_size = int(environ.get('CONTENT_LENGTH', '0'))    # request body 길이
    request_body = environ['wsgi.input'].read(request_body_size)    # 길이만큼 request body 읽기
    d = parse_qs(request_body)

POST를 사용해보기 위해서는 두 개의 터미널만 필요하다. 브라우저 창은 필요 없다. 한 개는 WSGI 서버를 실행하고 다른 한 개로 POST 요청을 한다.

POST 요청할 때는 curl을 이용한다.

실행해보면 아래와 같이 된다.

 

728x90

'개념 정리' 카테고리의 다른 글

영상 처리의 세 가지 기본 연산  (2) 2022.09.21
Git(2)  (0) 2022.07.06
Git(1)  (0) 2022.07.05
Python의 list, tuple, dictionary, set  (0) 2022.07.02
re 모듈과 같이 정규식 이해하기(Python)  (0) 2022.06.23