Вступление¶
ASGI является духовным наследником WSGI, давнего стандарта Python для совместимости между веб-серверами, фреймворками и приложениями.
WSGI удалось предоставить гораздо больше свободы и инноваций в веб-пространстве Python, и цель ASGI - продолжить эту работу асинхронным Python.
Что не так с WSGI?¶
Вы можете спросить «почему бы просто не обновить WSGI»? Об этом много раз спрашивали на протяжении многих лет, и проблема обычно заключается в том, что одновызываемый интерфейс WSGI просто не подходит для более сложных веб-протоколов, таких как WebSocket.
Приложения WSGI представляют собой единый синхронный вызов, который принимает запрос и возвращает ответ; это не учитывает долгоживущие соединения, такие, какие вы получаете с соединениями HTTP или WebSocket с длительным опросом.
Даже если мы сделали этот вызываемый асинхронным, он все равно имеет только один путь для предоставления запроса, поэтому протоколы, которые имеют несколько входящих событий (например, получение фреймов WebSocket), не могут инициировать это.
Как работает ASGI?¶
ASGI структурирован как единый асинхронный вызов. Он принимает scope
, который содержит подробную информацию о входящем запросе, send
, awaitable, которое позволяет отправлять события клиенту, и receive
, awaitable, которое позволяет получать события от клиента.
Это не только разрешает множественные входящие события и исходящие события для каждого приложения, но также позволяет использовать фоновую подпрограмму, чтобы приложение могло выполнять другие действия (например, прослушивание событий по внешнему триггеру, например очереди Redis).
В простейшей форме приложение может быть написано как функция, например:
async def application(scope, receive, send):
event = await receive()
...
await send({"type": "websocket.send", ...})
Каждое событие, которое вы отправляете или получаете, представляет собой тип dict
Python, с предопределенным форматом. Именно эти форматы событий составляют основу стандарта и позволяют выполнять обмен приложениями между серверами.
Каждое из этих событий имеет определенный ключ type
, который можно использовать для определения структуры события. Вот пример события для отправки начала ответа HTTP, который вы можете получить из receive
:
{
"type": "http.response.start",
"status": 200,
"headers": [(b"X-Header", b"Amazing Value")],
}
И вот пример события, которое вы можете передать send
для отправки исходящего сообщения WebSocket:
{
"type": "websocket.send",
"text": "Hello world!",
}
Совместимость с WSGI¶
ASGI также разработан как расширенный набор WSGI, и существует определенный способ перевода между ними, позволяющий запускать приложения WSGI на серверах ASGI через оболочку перевода (предоставляется в библиотеке asgiref
). Пул потоков можно использовать для запуска синхронных приложений WSGI из цикла асинхронных событий.