REST (REpresentational State Transfer) изначально проектировался для синхронного обмена данными, но иногда требуется асинхронное взаимодействие — например, для выполнения долгих операций или обработки задач в фоне. Разберем, как это работает и на что обратить внимание.
Как работает асинхронный REST?
1. Клиент инициирует задачу
Клиент отправляет запрос на сервер, чтобы запустить длительную операцию (например, генерацию отчета).
Пример запроса:
POST /api/reports
Content-Type: application/json
{ "type": "sales", "period": "2023" }
2. Сервер принимает запрос и возвращает статус «в обработке»
Сервер не блокирует клиента, а сразу отвечает:
{
"status": "accepted",
"task_id": "12345",
"status_url": "/api/reports/status/12345"
}
3. Клиент отслеживает статус задачи
Клиент периодически опрашивает status_url, чтобы узнать результат:
GET /api/reports/status/12345
Ответы сервера:
- {"status": "processing", "progress": 30%}
- {"status": "completed", "result_url": "/api/reports/download/12345"}
4. Получение результата
Когда задача завершена, клиент запрашивает данные по result_url.
Основные подходы к реализации
1. Polling (опрашивание)
- Как работает: Клиент периодически отправляет запросы на проверку статуса.
- Плюсы: Простота реализации.
- Минусы: Высокий трафик, задержки в получении результата.
2. Long Polling
- Как работает: Клиент отправляет запрос, а сервер держит его открытым, пока задача не завершится (или не истечет таймаут).
- Плюсы: Меньше запросов, быстрее получение результата.
- Минусы: Ресурсоемко для сервера.
3. Callback (вебхуки)
- Как работает: Клиент указывает URL (callback_url), куда сервер отправит результат.
Пример запроса:
{
"type": "sales",
"callback_url": "https://client.com/api/results"
}
- Плюсы: Нет лишних запросов.
- Минусы: Клиент должен иметь свой API для приема ответов.
4. Использование очередей (RabbitMQ, Kafka)
- Как работает: Сервер помещает задачу в очередь. Отдельный воркер обрабатывает её и сохраняет результат, доступный через REST.
- Плюсы: Масштабируемость, отказоустойчивость.
- Минусы: Сложность настройки.
На что обратить внимание?
1. Идемпотентность
- Повторная отправка одного запроса не должна создавать дублирующих задач.
- Решение: Используйте уникальные idempotency_key в заголовках.
2. Таймауты и повторные попытки
- Сервер должен учитывать время выполнения задачи и уметь перезапускать её при сбоях.
- Клиент — обрабатывать ошибки сети и повторять запросы.
3. Статусы задач
Четко определите возможные статусы:
- accepted (задача принята),
- processing (в процессе),
- completed (успешно),
- failed (ошибка).
4. Прогресс выполнения
Возвращайте клиенту progress в процентах или этапах, чтобы улучшить UX.
5. Очистка результатов
- Храните результаты не вечно. Удаляйте их через заданное время (TTL).
- Уведомляйте клиента, если результат удален.
6. Безопасность
- Для callback-URL используйте HTTPS и проверяйте подпись запросов.
- Защищайте task_id от подбора (используйте UUID вместо инкрементных чисел).
Пример асинхронного REST API
Шаг 1: Запуск задачи
POST /api/tasks
Content-Type: application/json
{
"type": "image_processing",
"image_url": "https://example.com/photo.jpg",
"callback_url": "https://client.com/callback"
}
Ответ:
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "accepted",
"links": {
"status": "/api/tasks/550e8400-e29b-41d4-a716-446655440000"
}
}
Шаг 2: Callback от сервера после завершения
POST https://client.com/callback
Content-Type: application/json
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result_url": "/api/results/processed_image.jpg"
}
Плюсы и минусы асинхронного REST
Плюсы
- Клиент не блокируется
- Подходит для долгих операций
- Уменьшает нагрузку на сервер
Минусы
- Сложнее реализовать, чем синхронный
- Требует механизма отслеживания статусов
- Риск потери callback-запросов
Когда использовать?
- Долгие задачи: Генерация отчетов, обработка видео, ML-инференс.
- Пиковые нагрузки: Чтобы избежать перегрузки сервера.
- Интеграция с внешними системами: Когда ответ может прийти с задержкой.
#rest #api #асинхронность #веб_разработка
Асинхронный REST — это мощный инструмент для работы с долгими операциями. Главное — продумать статусы, обработку ошибок и безопасность. Для упрощения используйте готовые решения вроде Celery (Python) или Bull (Node.js).