Uvicorn – ASGI-сервер для FastAPI и Django

онлайн тренажер по питону
Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Uvicorn: Полное руководство по высокопроизводительному ASGI-серверу

Что такое Uvicorn

Uvicorn — это современный, легковесный и высокопроизводительный ASGI-сервер, написанный на Python. Он специально разработан для запуска асинхронных веб-приложений и является одним из самых быстрых серверов для Python-приложений. Uvicorn построен на базе библиотек uvloop и httptools, что обеспечивает исключительную производительность при обработке большого количества одновременных запросов.

Сервер поддерживает современные веб-протоколы и технологии, включая HTTP/1.1, WebSocket, и может работать с любыми ASGI-совместимыми фреймворками, такими как FastAPI, Starlette, Django Channels и другими.

Основные преимущества и особенности

Архитектурные преимущества

Uvicorn представляет собой значительный шаг вперед в области веб-серверов Python благодаря следующим особенностям:

Асинхронность на уровне ядра — использует событийно-ориентированную архитектуру, позволяющую обрабатывать тысячи одновременных соединений с минимальными затратами ресурсов.

Высокая производительность — благодаря интеграции с uvloop (быстрая реализация asyncio) и httptools (быстрый HTTP-парсер), Uvicorn демонстрирует производительность, сравнимую с серверами на Go и Node.js.

Поддержка современных протоколов — нативная поддержка WebSocket, HTTP/1.1, а также возможность работы с HTTP/2 через дополнительные прокси.

Минимальные системные требования — оптимизирован для работы как на локальных машинах разработчиков, так и на продакшн-серверах.

Технические особенности

Uvicorn реализует спецификацию ASGI 3.0, что делает его совместимым с широким спектром современных Python-фреймворков. Сервер поддерживает автоматическое обнаружение изменений в коде во время разработки, многопроцессорный режим для продакшена и гибкую систему конфигурации.

Сравнение ASGI и WSGI

Понимание различий между ASGI и WSGI критически важно для выбора подходящего сервера:

Характеристика WSGI (Web Server Gateway Interface) ASGI (Asynchronous Server Gateway Interface)
Модель выполнения Синхронная, блокирующая Асинхронная, неблокирующая
Поддержка async/await Нет Полная поддержка
WebSocket Не поддерживается Нативная поддержка
HTTP/2 Ограниченная поддержка Полная поддержка
Фоновые задачи Требуют отдельных процессов Встроенная поддержка
Производительность Ограничена количеством потоков Высокая благодаря событийному циклу
Примеры серверов Gunicorn, uWSGI, mod_wsgi Uvicorn, Hypercorn, Daphne
Фреймворки Flask, Django (до 3.0), Bottle FastAPI, Starlette, Django 3.0+, Quart

ASGI является эволюционным развитием WSGI, предназначенным для современных веб-приложений, требующих высокой производительности и поддержки real-time функций.

Установка и первоначальная настройка

Установка через pip

pip install uvicorn

Установка с дополнительными зависимостями

# Для максимальной производительности
pip install uvicorn[standard]

# Включает uvloop, httptools, websockets, watchgod, python-dotenv

Минимальный пример приложения

Создайте файл main.py:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Привет от Uvicorn", "status": "working"}

@app.get("/health")
async def health_check():
    return {"status": "healthy"}

Запуск сервера

# Базовый запуск
uvicorn main:app

# Запуск с автоперезагрузкой для разработки
uvicorn main:app --reload

# Запуск на всех интерфейсах
uvicorn main:app --host 0.0.0.0 --port 8000

Детальный обзор параметров командной строки

Основные параметры запуска

uvicorn main:app \
  --host 0.0.0.0 \
  --port 8000 \
  --reload \
  --workers 4 \
  --log-level info

Полная таблица параметров

Параметр Описание Значение по умолчанию
--host IP-адрес для привязки сервера 127.0.0.1
--port Порт для прослушивания 8000
--reload Автоперезагрузка при изменении файлов False
--workers Количество рабочих процессов 1
--log-level Уровень логирования (trace, debug, info, warning, error, critical) info
--access-log Включить логирование доступа True
--proxy-headers Доверять заголовкам прокси (X-Forwarded-For, X-Forwarded-Proto) False
--root-path Корневой путь для приложения ""
--ssl-keyfile Путь к SSL приватному ключу None
--ssl-certfile Путь к SSL сертификату None
--ssl-version Версия SSL протокола TLSv1.2
--ssl-ca-certs Путь к CA сертификатам None
--ssl-ciphers Список разрешенных SSL шифров TLSv1.2
--loop Тип событийного цикла (auto, asyncio, uvloop) auto
--http HTTP протокол (auto, h11, httptools) auto
--ws WebSocket протокол (auto, none, websockets, wsproto) auto
--lifespan Поддержка ASGI lifespan событий (auto, on, off) auto
--reload-dir Директории для отслеживания изменений текущая
--reload-delay Задержка перед перезапуском (секунды) 0.25

Программный запуск Uvicorn

Базовый программный запуск

import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Программный запуск Uvicorn"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Расширенная конфигурация

import uvicorn
from fastapi import FastAPI

app = FastAPI()

if __name__ == "__main__":
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info",
        access_log=True,
        workers=1,  # workers > 1 несовместимо с reload=True
        loop="asyncio",
        http="auto",
        ws="auto",
        lifespan="auto",
        ssl_keyfile=None,
        ssl_certfile=None,
        proxy_headers=False,
        forwarded_allow_ips=None,
        root_path="",
        timeout_keep_alive=5,
        timeout_notify=30,
        limit_concurrency=None,
        limit_max_requests=None,
        backlog=2048,
        reload_dirs=None,
        reload_delay=0.25,
        reload_excludes=None,
        reload_includes=None
    )

Интеграция с различными фреймворками

FastAPI

FastAPI и Uvicorn созданы для совместной работы:

from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI(title="FastAPI + Uvicorn", version="1.0.0")

@app.get("/")
async def root():
    return {"framework": "FastAPI", "server": "Uvicorn"}

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id, "server": "Uvicorn"}

# Запуск: uvicorn main:app --reload

Starlette

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

async def homepage(request):
    return JSONResponse({"message": "Starlette + Uvicorn"})

routes = [
    Route("/", homepage),
]

app = Starlette(routes=routes)

# Запуск: uvicorn main:app --reload

Django ASGI

Для Django 3.0+:

# asgi.py
import os
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = get_asgi_application()
# Запуск Django через Uvicorn
uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000

Quart

from quart import Quart, jsonify

app = Quart(__name__)

@app.route("/")
async def hello():
    return jsonify({"message": "Quart + Uvicorn"})

# Запуск: uvicorn main:app --reload

Работа с WebSocket

Базовый WebSocket с FastAPI

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Test</title>
</head>
<body>
    <h1>WebSocket Test</h1>
    <input type="text" id="messageInput" placeholder="Введите сообщение">
    <button onclick="sendMessage()">Отправить</button>
    <ul id="messages"></ul>
    <script>
        const ws = new WebSocket("ws://localhost:8000/ws");
        
        ws.onmessage = function(event) {
            const messages = document.getElementById('messages');
            const message = document.createElement('li');
            message.textContent = event.data;
            messages.appendChild(message);
        };
        
        function sendMessage() {
            const input = document.getElementById('messageInput');
            ws.send(input.value);
            input.value = '';
        }
    </script>
</body>
</html>
"""

@app.get("/")
async def get():
    return HTMLResponse(html)

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Echo: {data}")
    except WebSocketDisconnect:
        print("Клиент отключился")

Продвинутый WebSocket с управлением соединениями

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from typing import List
import json

app = FastAPI()

class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

manager = ConnectionManager()

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            message = json.loads(data)
            await manager.send_personal_message(f"Client {client_id}: {message['text']}", websocket)
            await manager.broadcast(f"Client {client_id} says: {message['text']}")
    except WebSocketDisconnect:
        manager.disconnect(websocket)
        await manager.broadcast(f"Client {client_id} left the chat")

Конфигурация для продакшена

Системный сервис (systemd)

Создайте файл /etc/systemd/system/myapp.service:

[Unit]
Description=MyApp Uvicorn Service
After=network.target

[Service]
Type=exec
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/var/www/myapp/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target

Активация:

sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

Supervisor

Конфигурация в /etc/supervisor/conf.d/myapp.conf:

[program:myapp]
command=/var/www/myapp/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
directory=/var/www/myapp
user=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/myapp/uvicorn.log
stderr_logfile=/var/log/myapp/uvicorn.error.log

Docker контейнер

FROM python:3.11-slim

WORKDIR /app

# Копируем requirements и устанавливаем зависимости
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Копируем код приложения
COPY . .

# Создаем пользователя для безопасности
RUN useradd --create-home --shell /bin/bash app && chown -R app:app /app
USER app

# Настраиваем переменные окружения
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1

# Открываем порт
EXPOSE 8000

# Команда по умолчанию
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

Docker Compose

version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - PYTHONUNBUFFERED=1
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db
    volumes:
      - ./app:/app
    restart: unless-stopped

  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=mydb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - web
    restart: unless-stopped

volumes:
  postgres_data:

Настройка обратного прокси

Nginx конфигурация

upstream uvicorn {
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 80;
    server_name example.com;
    
    # Перенаправление на HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    client_max_body_size 64M;
    
    location / {
        proxy_pass http://uvicorn;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;
    }
    
    location /ws {
        proxy_pass http://uvicorn;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Traefik конфигурация

# docker-compose.yml
version: '3.8'

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=admin@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt

  web:
    build: .
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.web.rule=Host(`example.com`)"
      - "traefik.http.routers.web.entrypoints=websecure"
      - "traefik.http.routers.web.tls.certresolver=myresolver"
      - "traefik.http.services.web.loadbalancer.server.port=8000"
    restart: unless-stopped

Мониторинг и логирование

Структурированное логирование

import logging
import json
import uvicorn
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import time

# Настройка логирования
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

app = FastAPI()

class StructuredLogger:
    def __init__(self):
        self.logger = logging.getLogger("structured")
        
    def log_request(self, request: Request, response_time: float, status_code: int):
        log_data = {
            "timestamp": time.time(),
            "method": request.method,
            "url": str(request.url),
            "user_agent": request.headers.get("user-agent"),
            "ip": request.client.host,
            "response_time": response_time,
            "status_code": status_code
        }
        self.logger.info(json.dumps(log_data))

structured_logger = StructuredLogger()

@app.middleware("http")
async def log_requests(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    structured_logger.log_request(request, process_time, response.status_code)
    return response

@app.get("/")
async def root():
    return {"message": "Логирование работает"}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")

Интеграция с Prometheus

from prometheus_client import Counter, Histogram, generate_latest
from fastapi import FastAPI, Request, Response
from fastapi.responses import PlainTextResponse
import time

REQUEST_COUNT = Counter('requests_total', 'Total requests', ['method', 'endpoint'])
REQUEST_LATENCY = Histogram('request_duration_seconds', 'Request latency')

app = FastAPI()

@app.middleware("http")
async def prometheus_middleware(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    
    REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path).inc()
    REQUEST_LATENCY.observe(process_time)
    
    return response

@app.get("/metrics")
async def metrics():
    return PlainTextResponse(generate_latest())

@app.get("/")
async def root():
    return {"message": "Метрики доступны на /metrics"}

Тестирование приложений

Тестирование с pytest

import pytest
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_root():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Привет от Uvicorn", "status": "working"}

def test_health_check():
    response = client.get("/health")
    assert response.status_code == 200
    assert response.json() == {"status": "healthy"}

@pytest.mark.asyncio
async def test_websocket():
    with client.websocket_connect("/ws") as websocket:
        websocket.send_text("test message")
        data = websocket.receive_text()
        assert data == "Echo: test message"

Нагрузочное тестирование

import asyncio
import aiohttp
import time

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.json()

async def load_test():
    url = "http://localhost:8000/"
    tasks = []
    
    async with aiohttp.ClientSession() as session:
        start_time = time.time()
        
        for i in range(1000):
            task = asyncio.create_task(fetch(session, url))
            tasks.append(task)
        
        results = await asyncio.gather(*tasks)
        end_time = time.time()
        
        print(f"Выполнено {len(results)} запросов за {end_time - start_time:.2f} секунд")
        print(f"RPS: {len(results) / (end_time - start_time):.2f}")

if __name__ == "__main__":
    asyncio.run(load_test())

Оптимизация производительности

Настройка рабочих процессов

import multiprocessing
import uvicorn
from fastapi import FastAPI

app = FastAPI()

def get_optimal_workers():
    """Определяет оптимальное количество воркеров"""
    cpu_count = multiprocessing.cpu_count()
    return (cpu_count * 2) + 1

@app.get("/")
async def root():
    return {"message": "Оптимизированный сервер"}

if __name__ == "__main__":
    workers = get_optimal_workers()
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        workers=workers,
        loop="uvloop",
        http="httptools",
        access_log=False,  # Отключаем для производительности
        timeout_keep_alive=30
    )

Оптимизация для конкретных задач

import uvicorn
from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()

# Для высокой нагрузки
PRODUCTION_CONFIG = {
    "host": "0.0.0.0",
    "port": 8000,
    "workers": 4,
    "loop": "uvloop",
    "http": "httptools",
    "access_log": False,
    "timeout_keep_alive": 30,
    "limit_concurrency": 1000,
    "backlog": 2048
}

# Для WebSocket приложений
WEBSOCKET_CONFIG = {
    "host": "0.0.0.0",
    "port": 8000,
    "workers": 1,  # WebSocket требует один процесс
    "loop": "uvloop",
    "ws": "websockets",
    "timeout_keep_alive": 60
}

@app.get("/")
async def root():
    return JSONResponse({"message": "Высокопроизводительный сервер"})

if __name__ == "__main__":
    uvicorn.run("main:app", **PRODUCTION_CONFIG)

Методы и функции Uvicorn

Основные методы и классы

Метод/Класс Описание Пример использования
uvicorn.run() Основная функция для запуска сервера uvicorn.run(app, host="0.0.0.0", port=8000)
uvicorn.Config() Класс конфигурации сервера config = uvicorn.Config(app, host="0.0.0.0")
uvicorn.Server() Класс сервера для расширенного управления server = uvicorn.Server(config)
uvicorn.main() Точка входа для CLI Используется командной строкой
uvicorn.workers.UvicornWorker Воркер для Gunicorn gunicorn -k uvicorn.workers.UvicornWorker

Подробная таблица параметров uvicorn.run()

Параметр Тип Описание Значение по умолчанию
app ASGI приложение Основное ASGI приложение Обязательный
host str IP адрес для привязки "127.0.0.1"
port int Порт для прослушивания 8000
uds str Unix domain socket None
fd int Файловый дескриптор None
loop str Тип событийного цикла "auto"
http str HTTP протокол "auto"
ws str WebSocket протокол "auto"
ws_max_size int Максимальный размер WebSocket сообщения 16777216
ws_ping_interval float Интервал WebSocket ping 20.0
ws_ping_timeout float Таймаут WebSocket ping 20.0
lifespan str Обработка ASGI lifespan "auto"
interface str Интерфейс ASGI "auto"
reload bool Автоперезагрузка при изменениях False
reload_dirs list Директории для отслеживания None
reload_includes list Файлы для включения в отслеживание None
reload_excludes list Файлы для исключения из отслеживания None
reload_delay float Задержка перед перезагрузкой 0.25
workers int Количество рабочих процессов 1
env_file str Путь к .env файлу None
log_config dict/str Конфигурация логирования None
log_level str Уровень логирования "info"
access_log bool Включить логирование доступа True
use_colors bool Использовать цветной вывод None
proxy_headers bool Доверять заголовкам прокси False
server_header bool Включить заголовок Server True
date_header bool Включить заголовок Date True
forwarded_allow_ips str Разрешенные IP для X-Forwarded-For None
root_path str Корневой путь приложения ""
limit_concurrency int Максимальное количество соединений None
limit_max_requests int Максимальное количество запросов None
timeout_keep_alive int Таймаут keep-alive 5
timeout_notify int Таймаут уведомления о завершении 30
callback_notify callable Функция уведомления None
ssl_keyfile str Путь к SSL ключу None
ssl_certfile str Путь к SSL сертификату None
ssl_keyfile_password str Пароль для SSL ключа None
ssl_version int Версия SSL ssl.PROTOCOL_TLS_SERVER
ssl_cert_reqs int Требования к сертификату ssl.CERT_NONE
ssl_ca_certs str Путь к CA сертификатам None
ssl_ciphers str Разрешенные шифры "TLSv1.2"
headers list Дополнительные заголовки None
factory bool Приложение как фабрика False
backlog int Размер очереди соединений 2048

Программные интерфейсы

import uvicorn
from fastapi import FastAPI

app = FastAPI()

# Метод 1: Простой запуск
uvicorn.run(app)

# Метод 2: Конфигурация через Config
config = uvicorn.Config(
    app,
    host="0.0.0.0",
    port=8000,
    log_level="info",
    access_log=True
)
server = uvicorn.Server(config)

# Метод 3: Асинхронный запуск
import asyncio

async def main():
    config = uvicorn.Config(app, host="0.0.0.0", port=8000)
    server = uvicorn.Server(config)
    await server.serve()

# Метод 4: Управление жизненным циклом
async def startup():
    config = uvicorn.Config(app, host="0.0.0.0", port=8000)
    server = uvicorn.Server(config)
    
    # Запуск в фоновом режиме
    await server.startup()
    
    # Остановка
    await server.shutdown()

if __name__ == "__main__":
    asyncio.run(main())

Сравнение с другими серверами

Производительность

Сервер Тип Запросов/сек Память (МБ) Поддержка WebSocket
Uvicorn ASGI 20000-40000 15-25 Да
Gunicorn WSGI 5000-15000 30-50 Нет
Hypercorn ASGI 18000-35000 20-30 Да + HTTP/2
Daphne ASGI 8000-15000 25-40 Да
uWSGI WSGI 10000-20000 20-35 Ограниченно

Функциональные возможности

Возможность Uvicorn Gunicorn Hypercorn Daphne
HTTP/1.1
HTTP/2 Через прокси Нет
WebSocket Нет
Автоперезагрузка Нет
Множественные воркеры
SSL/TLS
Производительность Высокая Средняя Высокая Средняя

Безопасность

Конфигурация SSL/TLS

import uvicorn
from fastapi import FastAPI

app = FastAPI()

# SSL конфигурация
SSL_CONFIG = {
    "ssl_keyfile": "/path/to/private.key",
    "ssl_certfile": "/path/to/certificate.crt",
    "ssl_ca_certs": "/path/to/ca-bundle.crt",
    "ssl_version": ssl.PROTOCOL_TLSv1_2,
    "ssl_cert_reqs": ssl.CERT_REQUIRED,
    "ssl_ciphers": "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA"
}

@app.get("/")
async def root():
    return {"message": "Безопасное соединение"}

if __name__ == "__main__":
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=443,
        **SSL_CONFIG
    )

Защита от атак

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

app = FastAPI()

# Ограничение скорости запросов
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["*"],
)

# Проверка доверенных хостов
app.add_middleware(
    TrustedHostMiddleware,
    allowed_hosts=["example.com", "*.example.com"]
)

@app.get("/")
@limiter.limit("10/minute")
async def root(request: Request):
    return {"message": "Защищенный эндпоинт"}

Часто задаваемые вопросы

Что такое Uvicorn и зачем он нужен?

Uvicorn — это высокопроизводительный ASGI-сервер для Python, предназначенный для запуска асинхронных веб-приложений. Он необходим для запуска современных фреймворков, таких как FastAPI, Starlette, и Django с поддержкой асинхронности. Uvicorn обеспечивает значительно более высокую производительность по сравнению с традиционными WSGI-серверами.

Чем Uvicorn отличается от Gunicorn?

Основные отличия заключаются в архитектуре и возможностях. Uvicorn поддерживает асинхронное программирование, WebSocket, и имеет более высокую производительность благодаря событийно-ориентированной архитектуре. Gunicorn является синхронным WSGI-сервером, но может использовать Uvicorn в качестве воркера для поддержки ASGI.

Можно ли использовать Uvicorn с Django?

Да, начиная с Django 3.0, фреймворк поддерживает ASGI. Вы можете запустить Django через Uvicorn, используя ASGI-приложение Django. Это позволяет использовать асинхронные view-функции и WebSocket в Django.

Как настроить Uvicorn для продакшена?

Для продакшена рекомендуется: использовать несколько воркеров, настроить обратный прокси (Nginx), отключить режим отладки, настроить SSL/TLS, использовать systemd или supervisor для управления процессами, и настроить мониторинг и логирование.

Поддерживает ли Uvicorn HTTP/2?

Uvicorn не поддерживает HTTP/2 напрямую, но может работать за обратным прокси (например, Nginx) с поддержкой HTTP/2. Для нативной поддержки HTTP/2 можно использовать Hypercorn в качестве альтернативы.

Как работает автоперезагрузка в Uvicorn?

Автоперезагрузка активируется флагом --reload и отслеживает изменения в файлах Python. При обнаружении изменений сервер автоматически перезапускается. Эта функция предназначена только для разработки и не должна использоваться в продакшене.

Сколько воркеров нужно для оптимальной производительности?

Рекомендуется использовать формулу: (количество CPU ядер × 2) + 1. Однако оптимальное количество зависит от характера приложения. Для I/O-интенсивных задач может быть эффективно больше воркеров, для CPU-интенсивных — меньше.

Как обрабатывать статические файлы в Uvicorn?

Uvicorn не предназначен для обслуживания статических файлов. Рекомендуется использовать CDN или обратный прокси (Nginx) для статики. В FastAPI можно использовать StaticFiles для разработки, но не для продакшена.

Заключение

Uvicorn представляет собой современное решение для запуска высокопроизводительных веб-приложений на Python. Его асинхронная архитектура, поддержка современных протоколов и отличная интеграция с популярными фреймворками делают его идеальным выбором для разработки современных веб-сервисов.

Сервер обеспечивает отличную производительность, простоту настройки и богатые возможности конфигурации, что делает его подходящим как для разработки, так и для продакшена. Поддержка WebSocket, интеграция с системами мониторинга и возможность масштабирования через множественные воркеры позволяют создавать надежные и производительные веб-приложения.

Выбор Uvicorn в качестве ASGI-сервера обеспечивает долгосрочную совместимость с развивающимися стандартами веб-разработки и гарантирует высокую производительность ваших Python-приложений.

Новости