HTTP для бэкенда: методы, статусы, заголовки, keep-alive, HTTP/2 и HTTP/3
↑ 1.1 Сети и протоколы для бэкенда · ← Предыдущая · → Следующая
Зачем это на собесе
API на ASP.NET Core — это HTTP. Интервьюер ждёт точного понимания семантики методов, статус-кодов, заголовков кэширования и разницы версий протокола. Базовая часть есть во фронтенд-теме, здесь — взгляд со стороны сервера.
Подтемы
- Методы: безопасные, идемпотентные, кэшируемые
- Статус-коды, которые нужно выбирать уверенно
- Заголовки: content negotiation, кэш, трассировка, прокси
- Keep-alive и соединения
- HTTP/2 и HTTP/3
Объяснение
Методы и их свойства
- Безопасные (не меняют состояние): GET, HEAD, OPTIONS.
- Идемпотентные (повтор даёт тот же итог): GET, HEAD, OPTIONS, PUT, DELETE.
- Не идемпотентные: POST, PATCH (в общем случае).
- Кэшируемые: GET и HEAD (иногда POST с явными заголовками).
Серверные следствия:
- GET не должен менять данные: прокси, браузеры и краулеры повторяют и префетчат GET.
- PUT — полная замена ресурса по известному id (upsert). PATCH — частичное изменение (JSON Merge Patch или JSON Patch).
- POST для создания возвращает
201 Created+ заголовокLocation+ тело созданного ресурса. - DELETE повторно →
204или404: оба варианта допустимы, главное — стабильность.
Статусы, которые должен уверенно выбирать бэкендер
200 OK,201 Created,202 Accepted(принято к асинхронной обработке, например генерация отчёта),204 No Content.304 Not Modified— при условных запросах.400 Bad Request— синтаксически кривой запрос.422 Unprocessable Entity— валидный JSON, но бизнес-валидация не прошла (часто используют 400 с ProblemDetails — договоритесь в команде).401— нет или невалиден токен (+ заголовокWWW-Authenticate).403— нет прав.404— ресурса нет (иногда и для скрытия существования ресурса без прав).409 Conflict— конфликт состояния (дубликат, optimistic concurrency).412 Precondition Failed— не совпалIf-Match.429 Too Many Requests+Retry-After.500— непредвиденная ошибка.502/504— проблема апстрима или прокси.503+Retry-After— сервис временно недоступен (перегрузка, деплой).
Заголовки
Content-Type/Accept— согласование формата (content negotiation).Authorization: Bearer <jwt>.- Кэш:
Cache-Control(no-store,private,max-age),ETag+If-None-Match,If-Matchдля оптимистичной конкурентности на запись. - Трассировка:
traceparent(W3C),X-Request-Id/X-Correlation-Id. - За прокси:
X-Forwarded-For,X-Forwarded-Proto(в ASP.NET Core нуженUseForwardedHeaders, иначе неверные схема и IP клиента).
Keep-alive и соединения
HTTP/1.1 держит TCP-соединение открытым для следующих запросов, но в каждый момент по нему идёт один запрос (head-of-line blocking на уровне HTTP). Kestrel ограничивает число соединений и таймауты простоя.
HTTP/2 и HTTP/3
- HTTP/2: бинарные фреймы, мультиплексирование потоков в одном TCP, сжатие заголовков HPACK, server push (устарел). Обязателен для gRPC.
- HTTP/3: QUIC поверх UDP, нет head-of-line blocking на транспорте, 0-RTT, миграция соединений. Kestrel поддерживает HTTP/3 (нужен TLS).
Примеры в ASP.NET Core
app.MapPost("/api/patients", async (CreatePatientDto dto, IPatientService svc, CancellationToken ct) =>
{
var created = await svc.CreateAsync(dto, ct);
return Results.Created($"/api/patients/{created.Id}", created); // 201 + Location
});
app.MapGet("/api/patients/{id:guid}", async (Guid id, IPatientService svc, HttpContext ctx, CancellationToken ct) =>
{
var patient = await svc.FindAsync(id, ct);
if (patient is null) return Results.NotFound();
var etag = $"\"{patient.Version}\"";
if (ctx.Request.Headers.IfNoneMatch == etag) return Results.StatusCode(StatusCodes.Status304NotModified);
ctx.Response.Headers.ETag = etag;
return Results.Ok(patient);
});
app.MapPost("/api/reports", (ReportRequest r, IReportQueue q) =>
{
var jobId = q.Enqueue(r);
return Results.Accepted($"/api/reports/{jobId}/status", new { jobId }); // 202 для долгих операций
});// Kestrel: включить HTTP/1.1, HTTP/2 и HTTP/3
builder.WebHost.ConfigureKestrel(k =>
k.ListenAnyIP(5001, o => { o.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; o.UseHttps(); }));Нюансы и подводные камни
- gRPC без TLS требует явного HTTP/2 (h2c) на порту. Смешивать на одном порту без TLS HTTP/1.1 и HTTP/2 нельзя (нет ALPN).
- 500 с текстом исключения наружу — утечка внутренностей. Отдавайте ProblemDetails без стектрейса в проде.
- Не возвращайте 200 с
{ success: false }: ломает мониторинг, ретраи и клиентов. Retry-Afterпомогает клиентам и балансировщикам корректно повторять.
Тестирование
Интеграционными тестами через WebApplicationFactory проверяйте статус, заголовки (Location, ETag) и тело, а не только сервисный слой.
var response = await client.PostAsJsonAsync("/api/patients", dto);
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.Headers.Location.Should().NotBeNull();Вопросы с ответами
Какие методы идемпотентны и почему это важно для бэкенда?
GET, HEAD, OPTIONS, PUT, DELETE. Клиенты, прокси и библиотеки ретраев могут повторять их безопасно. Для POST нужна дедупликация через Idempotency-Key.
Какой статус вернуть при создании ресурса? При долгой асинхронной операции?
201 Created с Location и телом. Для долгой операции — 202 Accepted со ссылкой на статус задачи.
Когда 400, 409, 422?
400 — некорректный запрос (формат, типы). 422 — формат верный, но не прошла бизнес-валидация. 409 — конфликт с текущим состоянием (дубликат, версия устарела).
Зачем gRPC нужен HTTP/2?
Мультиплексирование потоков, бинарные фреймы, trailers для статусов и двунаправленный стриминг есть только в HTTP/2 и выше.
Что сломается без UseForwardedHeaders за nginx?
Приложение увидит IP прокси вместо клиента и схему http вместо https: неверные редиректы, ссылки, логи и ограничения по IP.
Связанные темы
- Предыдущая: Модель OSI и TCP∕IP, TCP и UDP · Следующая: TLS, сертификаты, mTLS
- HTTP со стороны фронта: HTTP∕HTTPS: методы, статусы, заголовки, HTTP∕2 и HTTP∕3
- Ответы и ProblemDetails: Ответы и ошибки: IResult, ProblemDetails, статус-коды
- REST-дизайн: Ресурсы, URL, методы и статусы: правила хорошего REST
- HTTP-кэширование: Кэширование HTTP: ETag, Cache-Control, output caching
- Идемпотентность: Идемпотентность и Idempotency-Key