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.