Этот топ-50 - компактный FAQ веб-разработчика, который закрывает базовые и собеседовательные темы: сеть и браузерные политики (включая что такое CORS), управление доступом (как работают cookie, сессии, JWT), хранение и кеширование, API-дизайн, производительность и деплой. В каждом блоке - короткие ответы и быстрые альтернативы для ограниченных ресурсов.
Краткие практические выводы по 50 вопросам веб-разработчика
- CORS - это не "фича сервера", а политика браузера: сервер лишь сообщает, кому разрешено читать ответ, через заголовки.
- Cookie ≠ LocalStorage: cookie ездят в каждом запросе (в пределах правил), а Web Storage - нет; значит, и угрозы/стоимость разные.
- JWT удобен для масштабирования, но не отменяет сессии: отзыв токена и ротация ключей - ваши обязанности.
- Кеширование - это слои: HTTP-кеш, CDN, Service Worker, app-кеш; начинайте с корректных заголовков.
- REST и GraphQL решают разные проблемы: выбирайте по профилю данных, кэшируемости и сложности клиента.
- Перфоманс чаще ломают мелочи: блокирующие ресурсы, лишний JS, некорректные приоритеты загрузки.
- Для малых команд важнее наблюдаемость, чем "идеальный CI/CD": логи+метрики+алерты дают больше эффекта, чем редкие релизы.
Сетевые механики и CORS: принцип, отладка и распространённые ошибки
Что такое CORS: это механизм, при котором браузер ограничивает доступ JS-кода страницы к ответам с другого origin (схема+хост+порт). Сервер может разрешить доступ, возвращая заголовки Access-Control-*. Если CORS не настроен, запрос может "уйти", но чтение ответа скриптом будет заблокировано.
CORS не является защитой сервера от запросов как таковых: любой клиент (curl, сервер-сервер, Postman) может обратиться к API. CORS защищает пользователя в браузере от нежелательного чтения ответов чужой страницей.
Preflight (OPTIONS) возникает, когда запрос "непростой" (например, нестандартные заголовки, методы, JSON с Content-Type: application/json). Браузер сначала проверяет, разрешён ли такой запрос, и только потом делает основной.
Практические вопросы (1-10): короткие ответы
- Что считается разным origin? Любое отличие в схеме, домене или порту:
https://a.comиhttp://a.com- разные origin. - Почему "CORS error" может быть из-за 500/502? Если сервер упал/прокси вернул ошибку без CORS-заголовков, браузер покажет CORS, потому что не может "прочитать" тело ошибки.
- Как быстро проверить CORS без браузера? Через curl увидеть заголовки:
curl -i https://api.example.com. Но помните: curl не применяет CORS-политику, он лишь показывает заголовки. - Какие заголовки минимально нужны? Обычно:
Access-Control-Allow-Origin. Для cookie/авторизации ещёAccess-Control-Allow-Credentials: trueи конкретный origin вместо*. - Почему нельзя
Allow-Origin: *вместе с credentials? Браузер запрещает: приcredentialsorigin должен быть конкретным, иначе это слишком широкий доступ. - Откуда берётся preflight? Из комбинации метода/заголовков/типа контента. Например,
Authorization: Bearer ...почти всегда вызывает preflight. - Как "починить" preflight на бэкенде? Отвечать на
OPTIONSбыстро и корректно: статус 204/200 +Access-Control-Allow-Methods,-Headers,-Origin. - Почему запрос работает в Postman, но не в браузере? Потому что Postman не ограничен CORS; это типичный сигнал, что проблема в политике браузера.
- Можно ли обойти CORS на фронтенде? В проде - нет "честного" обхода. Используют прокси (BFF/реверс-прокси) или переносят запрос на сервер.
- Дешёвая альтернатива при ограниченных ресурсах? Поставить один общий домен и проксировать API через Nginx/Caddy, чтобы все запросы стали same-origin.
Чек-лист диагностики CORS (быстро)

- Проверьте, есть ли
Access-Control-Allow-Originна реальном ответе и на ответе preflight (OPTIONS). - Сверьте origin запроса в DevTools → Network → Request Headers: схема/домен/порт.
- Если используются cookie/авторизация: включены ли
credentialsна клиенте иAllow-Credentialsна сервере. - Убедитесь, что прокси/балансер не "съедает" CORS-заголовки на ошибках.
Управление состоянием доступа: куки, сессии, JWT и безопасные практики
Состояние доступа - это способ связать запрос с пользователем: через cookie+сессию на сервере, через токены (JWT/opaque) на клиенте, или гибридно. Ключевая разница - где хранится "истина" (на сервере или в токене) и как выполняется отзыв.
- Cookie + серверная сессия: браузер хранит идентификатор, сервер хранит состояние (в памяти/Redis/БД). Плюс - простой отзыв; минус - хранение состояния и масштабирование.
- JWT: токен несёт данные и подпись. Плюс - меньше серверного состояния; минус - отзыв сложнее (нужны списки блокировки/короткие TTL/ротация).
- Opaque token: "непрозрачный" токен, проверяется сервером. Часто удобен как компромисс для контроля и аналитики.
- Refresh/Access токены: короткоживущий access + более долгий refresh снижает ущерб при утечке access.
- CSRF: актуален, когда авторизация автоматом едет в cookie. Для токенов в заголовке риск обычно иной (часто ближе к XSS/утечкам).
- XSS: угроза для всего, что читает JS. Поэтому секреты в LocalStorage - сомнительная идея для браузерных приложений с риском XSS.
Практические вопросы (11-20): короткие ответы
- Как работают cookie? Сервер ставит
Set-Cookie, браузер хранит и автоматически отправляет cookie обратно по правилам домена/пути/срока и атрибутов. - Когда cookie не поедут в запросе? Если домен/путь не совпали, истёк срок, запрещено по
SameSite, или кросс-доменный запрос безcredentials. - Что выбрать для SPA: cookie-сессия или JWT? Если нужен простой отзыв и контроль - cookie+сессия. Если много сервисов и нужен статлес - JWT/opaque + продуманная ротация.
- Зачем
HttpOnly? Чтобы JS не мог прочитать cookie (снижает ущерб от XSS для cookie). - Зачем
Secure? Чтобы cookie отправлялась только по HTTPS. - Что делает
SameSite? Ограничивает отправку cookie в кросс-сайтовых контекстах (важно для CSRF и сторонних встраиваний). - Почему "вышли из аккаунта", но JWT ещё работает? Потому что токен валиден до истечения. Нужен отзыв: короткий TTL, blacklist, смена ключа подписи или серверная проверка состояния.
- Дешёвый минимум безопасности при малых ресурсах? Cookie-сессия +
HttpOnly/Secure/SameSite, CSRF-токен для небезопасных методов, строгая CSP по возможности. - Можно ли хранить JWT в LocalStorage? Можно технически, но это делает токен доступным JS и уязвимым при XSS; предпочтительнее HttpOnly cookie или opaque token с серверной проверкой.
- Нужны ли подписи/шифрование в JWT? Подпись - да (JWS) для целостности. Шифрование (JWE) - только если действительно нужно скрывать содержимое и вы готовы к усложнению.
Чек-лист безопасной авторизации
- Для cookie включены
HttpOnly,Secure, корректныйSameSite, минимальныйPath/Domain. - Определён механизм отзыва (сессии/blacklist/короткий TTL + refresh).
- CSRF закрыт там, где cookie отправляются автоматически.
- XSS-риски снижены (экранирование, CSP, запрет inline где возможно).
Хранение и кеширование: LocalStorage, IndexedDB, HTTP-кеш и CDN
Хранение в браузере решает офлайн/ускорение/снижение нагрузки на сеть, но требует дисциплины: что именно кешировать, как инвалидировать и что делать при рассинхронизации. Начинайте с HTTP-кеша и правильных заголовков, а более сложные слои добавляйте по необходимости.
Типичные сценарии применения (21-30)
- Где уместен LocalStorage? Для несекретных небольших настроек (тема, флаги UI), где не критична транзакционность.
- Где лучше IndexedDB? Для структурированных данных, офлайн-очередей, кеша API-ответов, когда нужен объём и запросы по ключам.
- Что кешировать через HTTP-заголовки? Статику (JS/CSS/изображения) и ответы, которые можно валидировать ETag/Last-Modified.
- Как быстро снизить трафик без сложного фронта? Включить CDN для статики и выставить долгий кеш для файлов с хешами в имени.
- Как отличить memory cache / disk cache / CDN? В DevTools видно, откуда пришёл ресурс; CDN - по заголовкам/домену, браузерный кеш - по статусу/пометкам о кешировании.
- Что делать при ограниченных ресурсах команды? Не писать Service Worker "ради галочки"; сначала настроить
Cache-Control, хеширование ассетов и CDN. - Можно ли кешировать API-ответы? Да, если данные публичные или корректно разделены по пользователям; используйте
Vary, учитывайте авторизацию и приватность. - Как инвалидировать кеш правильно? Для статики - контент-хеш в имени файла; для данных - ETag/версионирование/TTL.
- Что хранить нельзя/опасно? Секреты (токены, пароли), персональные данные без необходимости, всё, что критично при XSS/компрометации устройства.
- Как понять, что кеш "сломался"? Симптомы: пользователи видят старый UI, 404 на ассеты, несовместимость API/фронта после релиза; лечится стратегией версионирования и хешами.
Чек-лист кеширования без лишней сложности
- Статика отдаётся с долгим
Cache-Controlи именами файлов с хешем. - API-ответы помечены как
private/publicосознанно; нет утечек через общий кеш. - Включена валидация (ETag/Last-Modified) там, где это уместно.
- Отдельно продуманы "обновления" клиента (версия приложения, миграции IndexedDB).
API и интеграции: REST vs GraphQL, обработка ошибок и версионирование
API-дизайн - это предсказуемость для клиента и управляемость для команды. Выбор REST или GraphQL влияет на кэш, дебаг и контракт. Для ограниченных ресурсов часто выигрывает простой REST с аккуратными ошибками и версионированием.
Плюсы, когда подход обычно выигрывает
- REST: проще проксировать и кэшировать на уровне HTTP/CDN; проще логировать; проще поддерживать без специализированного гейтвея.
- GraphQL: удобен при разнообразных клиентах и сложных графах данных, когда важно уменьшать overfetch/underfetch (но цена - сложнее сервер, кеш и безопасность запросов).
- Webhook: полезен для интеграций "событиями", снижает опрос; требует ретраев, подписи и идемпотентности.
- BFF (Backend For Frontend): часто самый прагматичный способ скрыть микросервисы и CORS, особенно если команда небольшая.
Ограничения и типовые ловушки
- REST: без дисциплины легко получить "RPC в REST-обёртке" и хаотичные эндпоинты; решается единым стилем ресурсов и кодов ошибок.
- GraphQL: риск дорогих запросов, N+1, необходимость лимитов сложности/глубины, сложнее кэш "из коробки".
- Ошибки: смешивание 200 + ошибка в теле ломает инструменты и ретраи; лучше согласовать статус-коды и формат тела.
- Версионирование: ломающее изменение без версии ведёт к авариям; при малых ресурсах проще всего версионировать путь (
/v1) и держать короткий период совместимости.
Практические вопросы (31-40): короткие ответы
- REST или GraphQL для небольшого продукта? Часто REST: дешевле в поддержке, проще кешировать, проще дебажить. GraphQL берите, когда реально болит агрегирование и вариативность запросов клиентов.
- Как оформлять ошибки? Единый формат: код/сообщение/детали, плюс корректный HTTP-статус (4xx/5xx). Сообщения для пользователя отделяйте от технических.
- Какие статусы важнее всего согласовать? 200/201/204, 400, 401, 403, 404, 409, 422 (если используете), 429, 500.
- Как делать идемпотентность? Для операций создания - ключ идемпотентности (заголовок/поле) и хранение результата на сервере.
- Как версионировать API без боли? Не ломать контракт; при необходимости -
/v2и параллельная поддержка. Для малой команды лучше реже и крупнее версии. - Как бороться с N+1? Батчинг/даталоадеры, правильные JOIN/агрегации, кеширование на уровне резолверов.
- Альтернатива GraphQL при ограниченных ресурсах? REST + эндпоинты-агрегаторы (BFF), или параметризованные include/expand, чтобы уменьшать число запросов.
- Что логировать на интеграциях? Корреляционный ID, статус, время, ретраи, внешний request-id, но без утечки секретов/PII.
- Как тестировать контракт? Контрактные тесты, схемы (OpenAPI), мок-сервер для клиента.
- Где уместны ретраи? На сетевых/временных сбоях и 429/503 с backoff; не ретраить 4xx (кроме случаев с обновлением токена).
Чек-лист надёжного API "без лишнего"
- Единый формат ошибок и понятные статусы.
- Версионирование и политика совместимости описаны и соблюдаются.
- Идемпотентность для критичных операций (платежи/создание заказов).
- Ограничения (rate limit) и наблюдаемость (корреляционные ID) включены.
Производительность фронтенда: загрузка ресурсов, рендеринг и оптимизация времени первой отрисовки
Оптимизация фронтенда - это управление критическим путём: что блокирует рендер, что занимает main thread, и что можно отложить. Часто лучший результат дают не сложные техники, а дисциплина сборки, корректные приоритеты загрузки и снижение объёма JS.
Типичные ошибки и мифы (41-47)
- Миф: "нужен SSR всегда". SSR помогает TTFB/первой отрисовке и SEO, но усложняет инфраструктуру. Для ограниченных ресурсов иногда достаточно пререндеринга статических страниц.
- Ошибка: один огромный bundle. Решение: code splitting по маршрутам/фичам и загрузка по требованию.
- Ошибка: блокирующие CSS/JS без приоритетов. Решение: минимальный критический CSS,
defer/asyncгде уместно, предзагрузка ключевых ресурсов. - Миф: "картинки не важны, всё решит CDN". Без правильных форматов/размеров CDN не спасёт. Делайте responsive images и оптимизацию формата.
- Ошибка: слишком много runtime-полифилов. Решение: таргетировать браузеры, отдавать дифференцированные бандлы, не тянуть лишнее.
- Ошибка: тяжёлые вычисления на main thread. Решение: Web Worker/разбиение задач, виртуализация списков.
- Миф: "оптимизируем только Lighthouse". Нужны реальные метрики (RUM) и профилирование под вашу аудиторию и устройства.
Практические вопросы (48-50): короткие ответы
- Что оптимизировать в первую очередь? Объём JS и блокировки рендера: меньше кода, меньше синхронных зависимостей, меньше работы на main thread.
- Какая дешёвая альтернатива сложному SSR? SSG/пререндер (например, сборка статических страниц) + CDN: проще и часто достаточно.
- Как быстро найти "тормоз"? DevTools Performance + Coverage, смотреть долгие tasks и неиспользуемый JS/CSS, затем резать по маршрутам.
Чек-лист быстрого фронта для небольшой команды
- Настроены code splitting и загрузка по требованию; нет "всего в одном бандле".
- Критические ресурсы имеют приоритет, блокирующие скрипты минимизированы.
- Изображения отдаются в подходящих размерах/форматах.
- Есть базовые RUM-метрики и регулярное профилирование.
Инфраструктура и деплой: CI/CD, контейнеризация, логирование и мониторинг приложений
Инфраструктура должна уменьшать риск релиза и ускорять обратную связь. Для ограниченных ресурсов важнее воспроизводимость (одинаковая сборка), быстрый откат и минимальная наблюдаемость, чем "идеальная" платформа. Начните с простого пайплайна, контейнера и стандартных логов.
Мини-кейс: деплой с минимальными затратами
Сценарий: один фронтенд и один API. Цель - каждый merge в main собирает образ, прогоняет тесты и выкатывает на сервер; откат - смена тега образа.
# Псевдопайплайн (смысл, не привязка к конкретному CI)
steps:
- checkout
- install && test
- build
- docker build -t registry/app:${GIT_SHA} .
- docker push registry/app:${GIT_SHA}
- ssh deploy@server "docker pull registry/app:${GIT_SHA} && docker compose up -d"
# Минимум для логов/трейсинга
# - писать логи в stdout/stderr (JSON по возможности)
# - прокидывать X-Request-Id и логировать его на всех сервисах
Практические вопросы: что сделать "сегодня"
- Нужны ли контейнеры? Почти всегда да: Docker упрощает воспроизводимость. Если ресурсов мало - начните хотя бы с одного Dockerfile.
- Что важнее: CD или CI? CI (тесты/сборка) обязателен; CD можно начать с полуавтомата (ручное подтверждение на прод).
- Что логировать в первую очередь? Ошибки, латентность, идентификатор запроса, пользователя (если допустимо), версию приложения, внешние вызовы.
- Дешёвая альтернатива сложному мониторингу? Централизованные логи + несколько ключевых метрик (ошибки, время ответа) + алерты по порогам.
- Как пережить "плохой релиз" с малыми ресурсами? Canary/blue-green - хорошо, но минимум: быстрый откат на предыдущий образ/артефакт и миграции БД с обратимостью.
Чек-лист самопроверки по всей странице (быстрый)
- Понимаете, почему CORS проявляется только в браузере и как читать preflight в Network.
- Для авторизации выбран один основной сценарий (cookie-сессия или токены) и определён отзыв/ротация.
- Кеширование начинается с HTTP/CDN и хеширования ассетов, а не с преждевременного Service Worker.
- Контракт API стабилен: ошибки, версии, идемпотентность и лимиты согласованы.
- Деплой воспроизводим, есть быстрый откат и минимальная наблюдаемость.
Разъяснения по 50 распространённым техническим вопросам
Почему CORS "ломается", хотя сервер отвечает 200?
Браузер может заблокировать доступ к ответу, если нет нужных Access-Control-* заголовков или не пройден preflight. В Network часто видно 200, но JS не получает данные.
Как понять, что проблема в SameSite у cookie?
Если кросс-сайтовый запрос перестал быть авторизованным, проверьте атрибут SameSite и режим запроса (credentials). Часто причина - смена схемы/домена или переход на встраивание в iframe.
Что выбрать для хранения токена, если боюсь XSS?
Обычно безопаснее HttpOnly cookie, потому что JS не читает её напрямую. При этом всё равно нужно снижать XSS-риски и продумать CSRF.
Почему REST "легче кешировать", чем GraphQL?
REST-ресурсы естественно мапятся на URL, и стандартный HTTP-кеш/CDN работает предсказуемо. В GraphQL часто всё идёт через один endpoint, и кэширование требует дополнительных слоёв/ключей.
Как отвечать на ошибки в API, чтобы клиент не гадал?

Возвращайте корректный HTTP-статус и стабильный формат тела ошибки (код, сообщение, детали). Не прячьте ошибки под 200, иначе ломаются ретраи и аналитика.
Какие "вопросы по JavaScript для собеседования" чаще всего упираются в браузерные механики?

Про event loop, микротаски/макротаски, замыкания и область видимости, прототипы, а также взаимодействие JS с сетью (fetch, CORS) и хранением (cookie, storage). Это часто проверяют через практические кейсы.



