Repository navigation
Service Gateway
Подробное описание реализованного API Gateway: назначение, стек, конфигурация, маршрутизация, безопасность и наблюдаемость.
- Назначение и роль в архитектуре
- Стек и зависимости
- Структура проекта
- Конфигурация (appsettings)
- Pipeline запроса: порядок middleware
- Маршрутизация (YARP)
- Аутентификация и авторизация
- Rate limiting
- CORS
- Health checks
- Наблюдаемость
- Окружения: Development и Production
- Запуск и развёртывание
TravelAgency.Gateway — единая точка входа для всех клиентских запросов к бэкенду. Сервис:
-
Принимает запросы по единому префиксу
/api/v1/.... - Проверяет JWT, применяет политики доступа (RBAC), лимиты запросов и CORS.
- Проксирует запросы к соответствующим бэкенд-сервисам (Identity, Catalog, Booking, Chat, Media) с преобразованием пути.
Собственной БД у Gateway нет; бизнес-логика в нём не размещается — только маршрутизация, проверка токена и политики доступа (в соответствии с архитектурными принципами).
| Компонент | Технология |
|---|---|
| Платформа | .NET 10, ASP.NET Core |
| Обратное проксирование | YARP (Yet Another Reverse Proxy) 2.3 |
| Аутентификация | JWT Bearer (Microsoft.AspNetCore.Authentication.JwtBearer) |
| Ограничение частоты запросов | AspNetCoreRateLimit 5.0 (in-memory) |
| Логирование | Serilog.AspNetCore 10 |
| Трейсинг | OpenTelemetry (AspNetCore + Hosting) |
| Общие контракты | TravelAgency.Shared.Contracts (роли, политики) |
src/Gateway/TravelAgency.Gateway/
├── Program.cs # Точка входа, регистрация сервисов и pipeline
├── TravelAgency.Gateway.csproj
├── appsettings.json # Конфиг по умолчанию (production-адреса сервисов)
├── appsettings.Development.json # Переопределение для локальной разработки
├── Dockerfile
├── Extensions/
│ ├── AuthenticationExtensions.cs # JWT + политики авторизации
│ ├── CorsExtensions.cs # CORS-политика
│ ├── HealthCheckExtensions.cs # Health checks + маппинг эндпоинтов
│ ├── ObservabilityExtensions.cs # Serilog + OpenTelemetry
│ ├── RateLimitingExtensions.cs # IpRateLimit
│ └── YarpExtensions.cs # Регистрация и маппинг YARP
├── HealthChecks/
│ └── DownstreamServiceHealthCheck.cs # HTTP-проверка доступности бэкендов
└── Middleware/
├── CorrelationIdMiddleware.cs # Correlation ID для трассировки
└── GlobalExceptionHandlerMiddleware.cs # Глобальная обработка ошибок (ProblemDetails)
Основные секции:
| Секция | Назначение |
|---|---|
| Serilog | Уровни логирования, шаблон вывода (в т.ч. {CorrelationId}), обогащение логов |
| JwtSettings | Issuer, Audience, SigningKey (≥32 символа), ValidateLifetime — для проверки JWT |
| ReverseProxy | Маршруты (Routes) и кластеры (Clusters) YARP — куда и как проксировать |
| IpRateLimiting | Лимиты по IP/эндпоинту, заголовки X-Forwarded-For / X-ClientId |
| Cors | AllowedOrigins, AllowedMethods, AllowedHeaders |
| HealthCheckEndpoints | URL эндпоинтов /health/live каждого бэкенда для readiness |
В Development переопределяются адреса кластеров (localhost:5010–5050), разрешённые origins (localhost:3000, 5173) и URL для health checks.
Порядок в Program.cs жёстко задан и влияет на поведение:
| № | Компонент | Назначение |
|---|---|---|
| 1 | Serilog Request Logging | Логирование входящего запроса |
| 2 | CorrelationIdMiddleware | Чтение/генерация X-Correlation-Id, запись в TraceIdentifier и в ответ, добавление в лог-контекст |
| 3 | GlobalExceptionHandlerMiddleware | Try/catch всего pipeline; при ошибке — ответ 500 в формате ProblemDetails (RFC 7807) |
| 4 | CORS | Проверка Origin, методов и заголовков по политике Gateway |
| 5 | IpRateLimiting | Проверка лимитов; при превышении — 429 |
| 6 | Authentication | Валидация JWT (если маршрут не Anonymous) |
| 7 | Authorization | Проверка политики, привязанной к маршруту YARP |
| — | MapHealthChecks | Эндпоинты /health/live и /health/ready (обрабатываются до YARP) |
| — | MapReverseProxy (YARP) | Выбор маршрута по пути/методу, трансформация пути, проксирование на бэкенд |
Итог: сначала идентификация запроса и обработка ошибок, затем CORS и лимиты, затем auth, затем маршрутизация на бэкенды.
Внешний API для клиента — единый префикс /api/v1. YARP по пути и методу выбирает маршрут, убирает префикс /api/v1, добавляет префикс сервиса и отправляет запрос в нужный кластер.
| Имя маршрута | Внешний путь | HTTP-методы | Политика доступа | Кластер (бэкенд) |
|---|---|---|---|---|
| auth-route | /api/v1/auth/{**catch-all} |
все | Anonymous | identity-cluster |
| catalog-public-route | /api/v1/catalog/{**catch-all} |
GET | Anonymous | catalog-cluster |
| catalog-manage-route | /api/v1/catalog/{**catch-all} |
POST, PUT, PATCH, DELETE | RequireManagerOrAdmin | catalog-cluster |
| bookings-route | /api/v1/bookings/{**catch-all} |
все | RequireClient | booking-cluster |
| favorites-route | /api/v1/favorites/{**catch-all} |
все | RequireClient | booking-cluster |
| chat-route | /api/v1/chat/{**catch-all} |
все | RequireClient | chat-cluster |
| media-route | /api/v1/media/{**catch-all} |
все | RequireClient | media-cluster |
Для каждого маршрута заданы преобразования:
-
PathRemovePrefix:
/api/v1— удаляется. -
PathPrefix: добавляется префикс сервиса (
/identity,/catalog,/bookings,/favorites,/chat,/media).
Примеры:
-
POST /api/v1/auth/login→ Identity Service:POST /identity/login -
GET /api/v1/catalog/tours→ Catalog Service:GET /catalog/tours -
GET /api/v1/bookings/my→ Booking Service:GET /bookings/my
В production адреса задаются в appsettings.json (имена контейнеров Docker, порт 8080):
-
identity-cluster →
http://identity-service:8080 -
catalog-cluster →
http://catalog-service:8080 -
booking-cluster →
http://booking-service:8080 -
chat-cluster →
http://chat-service:8080 -
media-cluster →
http://media-service:8080
В development те же кластеры переопределяются в appsettings.Development.json на http://localhost:5010 … 5050.
- Схема по умолчанию: JwtBearer.
- Параметры валидации: Issuer, Audience, SigningKey (минимум 32 символа), проверка срока жизни токена, роль из claim
Role. - Конфигурация в секции
JwtSettings; при отсутствии или коротком ключе приложение не запускается.
Политики заданы в AuthenticationExtensions.AddGatewayAuthorization и используют константы из TravelAgency.Shared.Contracts:
| Политика | Роли |
|---|---|
| RequireClient | Client, Manager, Admin |
| RequireManager | Manager, Admin |
| RequireAdmin | Admin |
| RequireManagerOrAdmin | Manager, Admin |
Привязка политики к маршруту задаётся в конфиге YARP (AuthorizationPolicy у каждого route). Маршруты auth и публичного каталога (GET) используют Anonymous; остальные — соответствующую политику (см. таблицу маршрутов выше).
- Библиотека: AspNetCoreRateLimit, хранилище — in-memory (MemoryCache).
- Идентификация клиента: по реальному IP из заголовка X-Forwarded-For и при необходимости X-ClientId (настраивается в
IpRateLimiting). - При превышении лимита возвращается HTTP 429.
Пример правил из конфига:
- Общий лимит: 100 запросов в 1 минуту на все эндпоинты (
*). -
POST /api/v1/auth/login: 20 запросов в 1 минуту. -
POST /api/v1/auth/register: 10 запросов в 1 минуту.
Дополнительные правила можно задать в секции IpRateLimitPolicies.
- Имя политики: GatewayPolicy (константа
CorsExtensions.GatewayCorsPolicyName). - В production по умолчанию разрешён origin:
https://travelagency.com. - В Development дополнительно разрешены:
http://localhost:3000,http://localhost:5173. - Разрешённые методы и заголовки (в т.ч.
Authorization,Content-Type,X-Correlation-Id) иAllowCredentials()задаются в секцииCorsи применяются ко всем ответам при использовании этой политики.
-
Liveness —
GET /health/live: предикат отключает все проверки; эндпоинт всегда отвечает «жив» (для оркестраторов/Kubernetes). -
Readiness —
GET /health/ready: выполняются проверки с тегом ready. Для каждого URL изHealthCheckEndpointsрегистрируется DownstreamServiceHealthCheck: HTTP GET к эндпоинту/health/liveсоответствующего бэкенда с таймаутом 5 секунд. Результат — Healthy (2xx) или Degraded (ошибка/исключение).
Таким образом, readiness Gateway показывает, доступны ли все настроенные бэкенд-сервисы.
-
Логи (Serilog): настройка из конфига, в шаблон вывода в консоль добавлен
{CorrelationId}. Обогащение: FromLogContext, WithMachineName, WithEnvironmentName. -
Трейсинг (OpenTelemetry): сервис регистрируется как
TravelAgency.Gateway, включена инструментация ASP.NET Core. Экспорт в Jaeger/OTLP настраивается отдельно при необходимости. -
Correlation ID: передаётся в заголовке ответа
X-Correlation-Idи в логах по всему запросу для связи логов и трейсов.
| Аспект | Production (appsettings.json) | Development (appsettings.Development.json) |
|---|---|---|
| Адреса бэкендов | Docker-имена: identity-service:8080, … |
localhost:5010 (Identity), 5020 (Catalog), 5030 (Booking), 5040 (Chat), 5050 (Media) |
| CORS Origins | https://travelagency.com |
+ http://localhost:3000, http://localhost:5173
|
| HealthCheckEndpoints | URL сервисов в Docker-сети | URL localhost с соответствующими портами |
| Уровень логов Serilog | Information (по умолчанию) | Debug; для Yarp — Debug |
-
Локально: запуск проекта TravelAgency.Gateway (например, из IDE или
dotnet runв каталоге проекта). Для работы маршрутов бэкенд-сервисы должны быть доступны по адресам изappsettings.Development.json. -
Docker: образ собирается по
Dockerfileв корне проекта Gateway; в Docker Compose сервис gateway обычно публикуется на одном порту (например, 5000 или 8080) и является единственной точкой входа для клиентов.
Проверка после запуска:
-
GET /health/live— 200. -
GET /health/ready— 200, если все бэкенды из HealthCheckEndpoints доступны; иначе Degraded. - Запрос к любому маршруту (например,
GET /api/v1/catalog/tours) при поднятых сервисах должен проксироваться на соответствующий бэкенд.
- Архитектура бэкенда — место Gateway в архитектуре и принцип «никакой бизнес-логики в Gateway».
-
Соответствие экранов и API — использование префикса
/api/v1и эндпоинтов с точки зрения фронтенда. - API-карта — детальные контракты по сервисам.
- Обзор проекта
- Архитектура и зависимости
- API-карта
- Gateway
- Identity
- Catalog
- Booking
- Chat
- Media
- gRPC контракты
- Архитектура
- Детали реализации
- Сервис API Gateway
- Сервис Identity
- Сервис Catalog
- ADR-001. Модель тура
- Сервис Booking
- Сервис Chat
- Сервис Media
- Содержимое сайта
- Стек и версии
- Глоссарий
- Соответствие экранов и API