ASGI

ASGI (Asynchronous Server Gateway Interface) — это стандарт взаимодействия между Python-веб-сервером и Python-приложением.

Если совсем грубо:

  • CGI — древний стандарт
  • WSGI — стандарт для синхронного Python-веба
  • ASGI — современный стандарт для асинхронного Python-веба

WSGI хорошо работал для классического веба:

Запрос
   ↓
Flask/Django
   ↓
Ответ

Но появились:

  • WebSocket
  • Server-Sent Events
  • long polling
  • стриминг
  • тысячи одновременных соединений

WSGI оказался ограничен, потому что предполагает модель:

request -> response

и всё.

Для постоянных соединений он не подходит.

Поэтому сообщество Python создало ASGI.


Главная идея

ASGI описывает договор между сервером и приложением.

Например:

Сервер:

  • Uvicorn
  • Hypercorn
  • Daphne

Приложение:

  • FastAPI
  • Starlette
  • Django ASGI
  • Quart

Они могут работать вместе, потому что говорят на одном языке — ASGI.


Как выглядит ASGI-приложение

Минимальное приложение:

async def app(scope, receive, send):
    ...

Всего три параметра.


scope

Описание соединения.

Например:

{
    "type": "http",
    "method": "GET",
    "path": "/users"
}

или

{
    "type": "websocket",
    "path": "/chat"
}

Это аналог метаданных запроса.


receive

Асинхронное получение событий.

message = await receive()

Например:

{
    "type": "http.request",
    "body": b"hello"
}

или

{
    "type": "websocket.receive",
    "text": "hi"
}

send

Отправка событий клиенту.

Например:

await send({
    "type": "http.response.start",
    "status": 200,
    "headers": [...]
})

Потом:

await send({
    "type": "http.response.body",
    "body": b"Hello"
})

Полный пример

async def app(scope, receive, send):

    await send({
        "type": "http.response.start",
        "status": 200,
        "headers": [
            [b"content-type", b"text/plain"]
        ]
    })

    await send({
        "type": "http.response.body",
        "body": b"Hello ASGI"
    })

Запуск через:

uvicorn main:app

Архитектура ASGI

Browser
   ↓
HTTP/WebSocket
   ↓
Uvicorn
   ↓
ASGI
   ↓
FastAPI
   ↓
Business Logic

или

Browser
   ↓
HTTP/WebSocket
   ↓
Hypercorn
   ↓
ASGI
   ↓
Starlette

Чем отличается от WSGI

WSGI:

def app(environ, start_response):
    ...

Синхронный вызов.


ASGI:

async def app(scope, receive, send):
    ...

Асинхронный вызов.


WSGI:

request
   ↓
response

ASGI:

event
event
event
event

То есть модель событийная.


Почему это важно для FastAPI

Когда ты пишешь:

@app.get("/users")
async def get_users():
    ...

На самом деле происходит цепочка:

FastAPI
  ↓
Starlette
  ↓
ASGI
  ↓
Uvicorn

FastAPI сам по себе сервером не является.

Он только ASGI-приложение.

Поэтому запуск выглядит так:

uvicorn main:app

где:

app = FastAPI()

— это объект ASGI-приложения.


Какие типы соединений умеет ASGI

HTTP

Обычные REST-запросы.

GET /users
POST /login

WebSocket

Постоянное двустороннее соединение.

Например:

@app.websocket("/chat")

Lifespan

События старта и остановки приложения.

Например:

@app.on_event("startup")

или в новых версиях:

async def lifespan(app):
    ...

Под капотом это тоже ASGI-события.


Что такое scope type

Внутри ASGI есть разные режимы:

scope["type"]

может быть:

"http"

или

"websocket"

или

"lifespan"

По этому значению приложение понимает, как обрабатывать соединение.


Самая важная мысль

ASGI — это не библиотека и не фреймворк.

Это именно протокол взаимодействия.

Примерно как HTTP определяет правила общения браузера и сервера, так ASGI определяет правила общения Python-сервера (например, Uvicorn) и Python-приложения (например, FastAPI).

Из-за этого ты можешь заменить:

Uvicorn

на

Hypercorn

или

Daphne

не переписывая приложение.

Они все реализуют один и тот же стандарт ASGI.

Прокрутить вверх