QA Interview Hub · База знань · Тести

API

Заголовки, кеш і CORS

Ключові заголовки

Заголовки — це метадані запиту й відповіді, і в них живе багато багів, які не видно в тілі.

ЗаголовокДеДля чого
Content-TypeЗапит і відповідьФормат тіла, наприклад application/json
AcceptЗапитЯкий формат клієнт хоче отримати
AuthorizationЗапитТокен або облікові дані
LocationВідповідьURL створеного ресурсу або редіректу
Cache-ControlВідповідьПравила кешування
ETagВідповідьВерсія ресурсу для кешу й конкурентних змін
Retry-AfterВідповідьКоли можна повторити запит після 429 чи 503
Set-CookieВідповідьВстановити cookie з атрибутами безпеки

Типові перевірки: Content-Type відповіді збігається з реальним вмістом; на Accept: application/xml, якщо API його не підтримує, сервер повертає 406, а не JSON мовчки; у Set-Cookie сесійної cookie є HttpOnly, Secure і SameSite; у відповіді немає заголовків, що розкривають версію сервера чи фреймворку.

На співбесіді: Я перевіряю не лише тіло, а й заголовки: Content-Type, Location після створення, правила кешу та атрибути безпеки cookie. Помилки в заголовках часто ламають клієнтів або створюють проблеми з безпекою.

ETag, 304 і Cache-Control

ETag — ідентифікатор версії ресурсу. Сервер віддає ETag: "v7". Наступного разу клієнт надсилає If-None-Match: "v7": якщо ресурс не змінився, сервер відповідає 304 Not Modified без тіла, і клієнт бере дані з кешу. Якщо змінився — 200 з новим тілом і новим ETag.

GET /accounts/42
If-None-Match: "v7"

HTTP/1.1 304 Not Modified
ETag: "v7"

ETag також захищає від втрачених оновлень: клієнт шле PUT з If-Match: "v7", і якщо хтось уже змінив ресурс, сервер повертає 412 Precondition Failed.

Cache-Control: no-cache vs no-store — класична пастка:

  • no-cache — зберігати можна, але перед використанням обов'язково перевірити актуальність на сервері (через ETag чи дату).
  • no-store — не зберігати взагалі, ні в браузері, ні в проміжних кешах.
  • max-age=60 — вважати відповідь свіжою 60 секунд; private — лише в браузері користувача, не в спільних кешах.

Для персональних і фінансових даних очікую no-store або щонайменше private, інакше баланс одного користувача може потрапити в CDN-кеш і віддатися іншому.

Тест-кейси: після зміни ресурсу ETag змінюється; старий ETag у If-None-Match дає 200, а не 304; відповіді з персональними даними не кешуються спільними кешами.

На співбесіді: ETag — версія ресурсу: з If-None-Match сервер повертає 304, якщо нічого не змінилося. no-cache означає «перевір перед використанням», а no-store — «не зберігай зовсім», і для фінансових даних я чекаю саме no-store.

CORS і preflight

CORS — механізм браузера, який дозволяє чи забороняє JavaScript на одному origin (схема + домен + порт) читати відповіді з іншого. Важливо: це обмеження саме браузера. Postman, curl і серверні клієнти CORS не застосовують, тому «в Postman працює, а в браузері ні» — типова ознака CORS-проблеми.

Для «непростих» запитів, наприклад з Content-Type: application/json, заголовком Authorization або методами PUT і DELETE, браузер спершу відправляє preflight — запит OPTIONS:

OPTIONS /api/transfers
Origin: https://app.bank.test
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type

Сервер має відповісти з Access-Control-Allow-Origin, Access-Control-Allow-Methods і Access-Control-Allow-Headers. Якщо чогось бракує, браузер не відправить основний запит, а в Console з'явиться CORS-помилка.

Що перевіряю:

  • Дозволений origin фронтенду отримує правильні заголовки, а сторонній — ні.
  • Немає Access-Control-Allow-Origin: * разом з передачею cookie чи токенів — браузер таке й так заблокує, а відображення будь-якого Origin назад у відповіді — дірка в безпеці.
  • Preflight повертає 2xx і не вимагає авторизації.
На співбесіді: CORS — захист браузера, тому в Postman його не видно. Для непростих запитів браузер спочатку шле preflight OPTIONS, і я перевіряю, що сервер дозволяє лише довірені origin і правильні методи й заголовки.