Редакция DDRW ·

Как устроен современный веб-сервис: от клика до ответа — 10 схем

Разбираем устройство веб-сервиса на примере интернет-магазина: браузер, сервер, база данных, Redis, сессии, оплата и фоновые задачи. Десять схем показывают путь от клика до подтверждённого заказа.

3D-иллюстрация веб-сервиса: окно браузера, серверные блоки и хранилище данных, соединённые прозрачными каналами

Покупатель открывает товар, выбирает размер, входит в аккаунт и оплачивает заказ. На экране это несколько понятных действий. Внутри сервиса работают браузер, сервер приложения, база данных, кеш, платёжная система и фоновые обработчики. Каждый отвечает за свою часть результата.

Хорошая архитектура описывает не только удачный путь. Она объясняет, что произойдёт, если товар закончился, ответ банка задержался или письмо не отправилось. Иначе удобный интерфейс скрывает неопределённость, которую затем приходится разбирать вручную.

Разберём устройство условного магазина по десяти схемам: от первого запроса карточки до оплаты, письма и восстановления после сбоя. Это учебный пример, а не описание проверенных свойств конкретного проекта DDRW. Не каждому магазину нужны отдельные серверы для всех блоков: небольшое приложение может объединять их в одном процессе, сохраняя понятные границы ответственности.

1. Путь запроса: что происходит после клика

Схема 1: путь запроса от браузера через сервер приложения к данным и обратно к пользователю

При открытии страницы браузер обращается к нужному адресу и получает HTTP-ответ: статус, заголовки и содержимое. Это может быть HTML карточки товара, изображение или данные для обновления интерфейса. Основной цикл «клиент запрашивает — сервер отвечает» разобран в введении MDN о работе веба.

Одна видимая страница обычно требует нескольких ресурсов. HTML задаёт структуру, CSS — оформление, изображения показывают товар, клиентский код обрабатывает выбор цвета. Часть ресурсов браузер может взять из собственного кеша, поэтому повторное открытие не обязательно повторяет весь сетевой путь.

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

В нашем магазине успешный ответ карточки ещё не означает, что покупку можно завершить. Между просмотром и оформлением способны измениться цена и остаток. Это разные операции с разными проверками.

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

2. DNS и HTTPS: найти адрес и защитить передачу

Схема 2: разрешение доменного имени через DNS и установка защищённого HTTPS-соединения

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

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

HTTPS использует TLS для защиты передачи между сторонами соединения. Браузер проверяет сертификат и домен, а участники согласуют защищённый обмен. Назначение и свойства TLS описаны в документации MDN.

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

Если TLS завершается на прокси, соединение от него до приложения рассматривают отдельно: где оно проходит, кто имеет к нему доступ и нужна ли дополнительная защита. Пароли, токены и данные покупателей нельзя считать защищёнными во всех внутренних компонентах только на основании HTTPS в адресной строке.

3. Frontend и backend: где принимается решение

Схема 3: разделение обязанностей браузерного интерфейса, серверной логики и хранилища данных

Frontend помогает человеку взаимодействовать с магазином. Он показывает доступные цвета, меняет фотографию, проверяет очевидные ошибки формы и объясняет результат действия. Backend применяет правила бизнеса и определяет, какие изменения допустимы.

Например, браузер может мгновенно показать предварительную сумму после нажатия «плюс». Но при оформлении сервер заново проверяет вариант товара, количество, действующую цену и условия заказа. Значению суммы, присланному клиентом, доверять нельзя: запрос можно отправить без интерфейса магазина.

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

Граница между frontend и backend не обязательно проходит между двумя отдельными приложениями. Сервер может формировать страницы и принимать обычные формы, а интерактивные элементы — обращаться к API. Важно, чтобы правило расчёта и разрешение операции имели авторитетную серверную реализацию.

Для оформления полезно разделять ошибки по смыслу. Неверный телефон нужно исправить в форме; закончившийся размер — выбрать заново; временный сбой платежей — переждать или использовать согласованный альтернативный путь. Универсальная надпись «Что-то пошло не так» не помогает продолжить покупку и затрудняет поддержку.

4. SSR, гидратация и интерактивность: что получает браузер

Схема 4: серверная подготовка HTML, гидратация интерактивных элементов и последующие переходы внутри приложения

При SSR сервер готовит HTML страницы до отправки в браузер. В карточке уже могут находиться название, описание, цена и основное изображение. Пользователю не обязательно ждать отдельного запроса к API только для появления этого текста.

Гидратация подключает клиентскую логику к серверному представлению. Она нужна там, где интерфейс должен реагировать без полной загрузки документа: менять фотографию варианта, открывать галерею или пересчитывать предварительную сумму. Различия подходов разобраны в материале web.dev о рендеринге.

SSR не означает отсутствие JavaScript. Приложение может одновременно отправлять готовый HTML и большой клиентский пакет. Объём кода, порядок загрузки и границы интерактивности остаются отдельными решениями.

Островная архитектура — один из способов ограничить интерактивность отдельными частями страницы. Например, описание товара остаётся статичным, а выбор размера и корзина получают собственную клиентскую логику. Это не обязательное свойство любого SSR-приложения.

В SPA внутренний переход может обновлять представление без перезагрузки всего документа. При этом сервер продолжает проверять запросы к данным и действиям. Для прямого открытия адреса также нужен корректный ответ: ссылка из поиска не обязана начинаться с главной страницы.

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

5. База данных и транзакции: сохранить согласованный заказ

Схема 5: проверка товара и остатков, создание снимка заказа и фиксация изменений в транзакции базы данных

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

Поэтому в заказе сохраняют снимок существенных условий: название, вариант, количество, цену и итог. Это отдельные данные момента покупки. Ссылка на текущий товар может оставаться, но не заменяет такой снимок.

Транзакция объединяет несколько изменений базы по принципу «всё или ничего». Если сохранение одной обязательной части завершилось ошибкой, остальные изменения этой операции не должны остаться частично применёнными. Объяснение транзакций PostgreSQL.

Для последнего доступного размера недостаточно сначала прочитать остаток, а позже отдельно уменьшить его. Два покупателя могут увидеть одно и то же значение. Нужен выбранный механизм конкурентного контроля: блокировка, условное обновление или другой согласованный способ. Поведение при конфликте проектируется явно.

В нашем примере сервер внутри короткой транзакции проверяет условия, создаёт заказ и резервирует товар по правилам магазина. Резерв имеет срок и понятный способ освобождения, если покупатель не оплатил.

Внешняя оплата не становится частью этой SQL-транзакции. Банк не откатит списание из-за отката базы магазина. Взаимодействие строят через отдельные состояния, сохранённые идентификаторы и последующее согласование результата. Держать транзакцию открытой, пока человек заполняет банковскую форму, также не следует.

6. Redis и кеш: ускорять чтение без потери правил

Схема 6: чтение каталога через Redis, обращение к базе при промахе и обновление кеша после изменения данных

В условном магазине Redis используется как восстановимая копия публичных данных каталога. Приложение сначала ищет готовое значение в кеше, а при отсутствии читает базу и подготавливает новую копию. Такой подход называется cache-aside. Описание подхода в документации Redis.

Ключ должен учитывать всё, что меняет результат: товар, фильтры, язык и версию формата данных. Общий кеш нельзя использовать для чужих корзин, закрытых заказов или персональных условий без соответствующего разделения.

При изменении товара важно дождаться успешного commit в базе. Если очистить кеш раньше, параллельный запрос может снова заполнить его старым значением. Но и простая команда удаления после commit не устраняет все гонки и сбои доставки уведомления.

Для более строгого контроля применяют версии данных и надёжную регистрацию события обновления. TTL ограничивает срок жизни копии, однако не обещает мгновенной свежести. Конкретную допустимую задержку и поведение при ошибке нужно определить заранее.

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

Если Redis недоступен, чтение каталога может перейти к базе, но это увеличит нагрузку. Нужны ограничения параллелизма и наблюдение: резервный путь не должен превращать короткий сбой кеша в перегрузку основного хранилища.

7. Сессии, cookies и права: узнавать пользователя и проверять действия

Схема 7: вход, создание сессии, передача защищённой cookie, проверка прав и защита изменяющих запросов от CSRF

Аутентификация отвечает на вопрос «Кто обращается?». Авторизация — «Что ему разрешено?». Вход в аккаунт не даёт покупателю доступа ко всем заказам: сервер проверяет владельца конкретного заказа при каждом соответствующем запросе.

Сессия связывает обращения браузера с подтверждённым входом. Cookie может содержать идентификатор сессии или защищённый токен — это зависит от архитектуры. В любом случае нужны срок действия, выход и возможность прекратить доступ в предусмотренных ситуациях.

HttpOnly ограничивает чтение cookie из JavaScript, Secure предназначен для передачи по защищённому соединению, SameSite помогает ограничивать отправку в межсайтовых сценариях. Эти свойства не заменяют проверку прав и остальные меры защиты приложения.

Браузер прикладывает подходящие cookies автоматически. Поэтому злоумышленник может попытаться инициировать изменяющее действие через чужую страницу. Для cookie-аутентификации нужны соответствующие меры против CSRF: проверка токена и происхождения запроса по выбранной схеме. Ограничения SameSite разобраны в рекомендациях OWASP.

В нашем магазине смена количества, создание заказа и изменение контактов проходят серверную проверку. Администраторские действия требуют собственных разрешений. Поля вроде user_id или role, пришедшие из браузера, не являются доказательством полномочий.

Доступ к гостевой корзине тоже нуждается в модели владения. Отсутствие регистрации не делает её общедоступной: сервер связывает корзину с выданным посетителю секретом и не показывает данные по одному угадываемому номеру.

8. Очередь и фоновые задачи: продолжить работу после ответа

Схема 8: запись фоновой задачи, получение обработчиком, повторные попытки и защита от повторного выполнения

После создания заказа не обязательно заставлять покупателя ждать отправки письма. Фоновый обработчик может выполнить её отдельно. Но сначала требуется надёжно сохранить саму необходимость отправки.

Один из подходов — записать заказ и событие для обработки в одной транзакции базы. Затем отдельный процесс читает события и выполняет задачи. Так промежуток между сохранением заказа и постановкой письма не зависит от того, успело ли приложение сделать второй сетевой вызов.

Доставку задачи нужно проектировать с возможностью повтора. Например, стандартные очереди Amazon SQS прямо допускают получение одного сообщения несколько раз и рекомендуют идемпотентную обработку. Документация at-least-once delivery.

Идемпотентность означает, что повтор не создаёт нежелательный дополнительный результат. Для обработки оплаченного заказа можно использовать уникальное событие, проверяемое состояние и ограничение в базе. Одна очередь сама по себе не обеспечивает выполнение бизнес-действия «ровно один раз».

С письмом сложнее: почтовый сервер мог принять сообщение, а подтверждение потерялось. Автоматическая повторная отправка способна создать дубль. Нужны состояние неопределённости, доступные идентификаторы доставки и предусмотренный порядок разбора.

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

9. API, оплата и webhooks: доверять подтверждённому событию

Схема 9: создание платёжной сессии, переход покупателя к провайдеру, проверка webhook и обновление статуса заказа

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

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

Состояние подтверждается проверенным серверным уведомлением либо авторизованным запросом статуса к провайдеру. Обработчик сопоставляет заказ, платёж, сумму, валюту и допустимый статус. Правила проверки подписи или токена зависят от интеграции; HTTPS и знакомое название поля не заменяют эту проверку.

Webhooks могут повторяться и поступать не в ожидаемом порядке. Необходимость проверки подлинности и обработки повторов показана в официальной документации Stripe. Это пример общих принципов; конкретный контракт выбранного банка проверяют отдельно.

В нашем магазине повторное подтверждение не должно ещё раз уменьшать остаток или создавать письмо. Уведомление обрабатывается транзакционно с сохранением результата. Успешный ответ провайдеру отправляется после надёжного принятия события; тяжёлые последующие действия можно выполнять фоном.

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

10. Развёртывание, наблюдаемость и восстановление

Схема 10: выпуск приложения, проверка готовности, наблюдение за запросами и восстановление базы и файлов из резервной копии

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

План выпуска учитывает изменения базы и возможность отката. Возврат старого приложения небезопасен, если новая миграция уже сделала данные с ним несовместимыми. Фоновые задачи и уведомления банка тоже могут продолжать поступать во время переключения.

Наблюдаемость помогает понять реальные причины сбоя. Метрики показывают частоту ошибок и задержки, логи — отдельные события, трассировка связывает участки выполнения запроса. Эти сигналы и их назначение описаны в введении OpenTelemetry.

Для магазина полезно видеть путь от создания заказа до подтверждения и отправки письма по связанным идентификаторам. При этом токены, платёжные секреты и полные персональные данные не должны становиться обычным содержимым журналов.

Резервная копия включает необходимые данные, загруженные файлы и сведения для запуска совместимой версии. Срок хранения и допустимую потерю последних изменений определяют заранее. PostgreSQL описывает разные подходы: дамп, файловую копию и непрерывное архивирование. Документация резервного копирования.

Наличие архива не подтверждает восстановление. Нужен отдельный проверенный сценарий: развернуть копию изолированно, проверить данные и файлы, открыть основные страницы. В такой среде отключают реальные отправки и финансовые действия, чтобы проверка не повторила рабочие операции.

Практический чек-лист

  • Сервер проверяет сумму, остатки и владельца данных независимо от интерфейса.
  • Заказ сохраняет условия покупки, а платёж имеет собственный идентификатор и состояние.
  • Общий кеш не содержит чужие корзины, доступы и персональные ответы.
  • Фоновые задачи и webhooks допускают безопасную повторную обработку.
  • Ошибки оплаты и отправки имеют понятный путь проверки и разрешения.
  • Выпуск учитывает совместимость базы, а восстановление проверено отдельно от создания копии.

Частые вопросы

Нужны ли сразу микросервисы? Нет. Перечисленные обязанности можно реализовать в одном приложении. Их физическое разделение оправдывается нагрузкой, независимым развитием и возможностями команды.

Достаточно ли Redis для скорости и надёжности? Нет. Кеш ускоряет выбранные чтения, но не исправляет медленные запросы, ошибки доступа и неверную обработку платежей. Сначала выясняют причину проблемы.

Что важнее проверить перед запуском? Полный путь и его сбои: товар изменился, запрос повторился, платёж задержался, письмо не отправилось, приложение перезапустилось. Именно поведение в этих ситуациях делает систему управляемой.

Услуги и проекты по теме

Обсудим вашу задачу

Расскажите о продукте и ожидаемом результате. Определим состав работ, предложим подход и согласуем сроки и стоимость.

Все материалы