Опишите шаги обработки HTTP-запроса от клиента до сервера и обратно.

«Опишите шаги обработки HTTP-запроса от клиента до сервера и обратно.» — вопрос из категории Сети, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Обработка HTTP-запроса — это многоуровневый процесс, охватывающий стек протоколов от приложения до сети.

Основные этапы:

  1. DNS-резолвинг: Браузер преобразует доменное имя (например, api.example.com) в IP-адрес сервера, запрашивая DNS-серверы.
  2. Установка TCP-соединения (3-way handshake): Клиент и сервер обмениваются пакетами SYN, SYN-ACK, ACK для установки надежного соединения.
  3. TLS handshake (для HTTPS): Если используется HTTPS, происходит согласование параметров шифрования и обмен сертификатами для установки защищенного TLS-туннеля.
  4. Формирование и отправка HTTP-запроса: Клиент формирует HTTP-сообщение (метод, заголовки, тело) и отправляет его по установленному соединению.
  5. Обработка на сервере приложений:
    • Веб-сервер (Nginx, IIS) принимает запрос и перенаправляет его в runtime приложения (например, Kestrel для .NET).
    • Запрос проходит через конвейер middleware ASP.NET Core (логирование, аутентификация, CORS).
    • Маршрутизатор направляет запрос в соответствующий метод контроллера (action method) на основе шаблона URL.
    • Модель связывания (Model Binding) преобразует данные запроса (из строки запроса, тела, заголовков) в параметры метода C#.
    • Выполняется бизнес-логика, часто с обращением к базе данных или внешним API.
  6. Формирование и отправка HTTP-ответа: Сервер формирует ответ (статус-код, заголовки, тело — часто JSON) и отправляет его обратно клиенту.
  7. Закрытие соединения: Соединение закрывается или сохраняется для повторного использования (keep-alive).

Пример упрощенного кода контроллера:

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")] // Маршрут: GET /api/products/5
    public async Task<ActionResult<Product>> GetProduct(int id)
    {
        var product = await _dbContext.Products.FindAsync(id);
        if (product == null)
        {
            return NotFound(); // HTTP 404
        }
        return Ok(product); // HTTP 200 с телом в JSON
    }
}