# wsgi_app_module1.py
from collections.abc import Callable, Iterable
def app(env: dict, start_response: Callable) -> Iterable[bytes]:
# env에 있는 입력 정보를 처리하여 출력 데이터 생성
data = b"Hello, World!"
# start_response 함수를 호출하여 상태, 헤더, 예외 전송
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data))),
])
# 결과를 이터러블 객체로 반환
return [data]
```파이썬 웹 서비스
WSGI 규약과 ASGI 규약
- 파이썬 웹서버는 웹 브라우저로부터 받은 호출에 따라 미리 정해진 파이썬 함수를 실행하고 그 결과를 다시 웹브라우저에게 전달한다.
- 이 때 호출될 파이썬 함수가 어떻게 구현되어 있어야 하고 이 함수를 어떤 식으로 호출하는가는 미리 정한 규약을 따라야 한다.
- WSGI(Web Server Gateway Interface) 규약은 동기적으로 파이썬 코드를 실행하는 경우 사용되는 규약
- ASGI(Asynchronous Server Gateway Interface) 규약은 비동기적으로 파이썬 코드를 실행하는 경우 사용되는 규약
WSGI 웹 서버
- WSGI 웹 서버에 제공되는 파이썬 함수는 다음과 같이 구현되어야 한다.
- WSGI 규약에 따라 만들어진 대표적인 웹 서버는 gunicorn 서버이다. (윈도우즈 OS에서는 사용불가)
- gunicorn 서버는 다음과 같이 웹서버 코드를 가진 모듈 이름과 함수 이름을 인수로 주어 가동한다.
- 모듈은 임포트 가능해야 한다. 즉 gunicorn 명령을 실행하는 디렉토리에 있거나 위치가 sys.path 경로내에 포함되어 있어야 한다.
$ gunicorn wsgi_app_module1:appASGI 웹 서버
- ASGI 웹 서버에 제공되는 파이썬 함수는 다음과 같이 구현되어야 한다.
- WSGI 규약과 달리 결과를 반환하지 않고 상태정보나 헤더정보처럼 send 함수로 보낸다.
# asgi_app_module1.py
from typing import Callable
async def app(
scope: dict,
receive: Callable,
send: Callable,
) -> None:
# body가 있는 경우 receive 함수를 호출하여 정보 입수
# event = await receive()
data = b"Hello, world!"
# 상태 코드와 헤더 전송
await send({
"type": "http.response.start",
"status": 200,
"headers": [(b"content-type", b"text/plain")],
})
# 응답 본문 전송
await send({
"type": "http.response.body",
"body": data,
})- ASGI 규약에 따라 만들어진 대표적인 웹 서버는 uvicorn 서버
- 가동 방식은 gunicorn과 같다.
$ unvicorn asgi_app_module1:app웹 프레임워크
- 웹 프레임워크는 웹 서버가 사용할 애플리케이션 코드를 구현하는 것을 도와주는 파이썬 패키지
- 복잡한 웹 애플리케이션을 구조화하여 개발할 수 있는 체계를 제공
- 웹 애플리케이션 구현시 공통적으로 필요한 로그인 처리, 세션 처리, 데이터베이스 연결 등에 필요한 자료구조나 함수 등을 제공
- 대표적 웹 프레임워크
- flask: 소형 웹 프레임워크. WSGI 지원
- django: 자체 ORM, 템플릿, 관리자 UI 등을 포함하는 풀스택 웹 프레임워크, WSGI/ASGI 모두 지원
- starlette: 소형 웹 프레임워크. ASGI 지원
starlette
- 비동기 ASGI 전용 웹 프레임워크
# starlette1.py
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.routing import Route
async def homepage(request):
return PlainTextResponse("Hello, world!")
app = Starlette(debug=True, routes=[
Route('/', homepage),
])