Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
HTTP: как работает протокол обмена данными
HTTP (HyperText Transfer Protocol) — это фундамент веб-разработки. За 10+ лет я понял, что глубокое понимание HTTP критично для оптимизации, дебагинга и архитектуры приложений. Разбираю от основ до практики.
1. Основы HTTP: Request-Response модель
HTTP работает по простому принципу: клиент отправляет запрос, сервер отправляет ответ.
// В браузере всё HTTP это по сути fetch() API
const httpRequest = async () => {
// ШАГИ
// 1. ESTABLISH CONNECTION (TCP handshake)
// - Браузер подключается к серверу по IP и портам
// - Для HTTPS добавляется SSL/TLS handshake
// 2. SEND REQUEST (отправка запроса)
const response = await fetch('https://api.example.com/users/123', {
method: 'GET', // HTTP метод
headers: { // HTTP заголовки
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({}), // Тело запроса (для POST/PUT)
// body не используется для GET
});
// 3. RECEIVE RESPONSE (получение ответа)
const status = response.status; // 200, 404, 500 итд
const headers = response.headers; // Заголовки ответа
const data = await response.json(); // Тело ответа
// 4. CLOSE CONNECTION (закрытие соединения)
// Обычно автоматически (HTTP/1.1 Keep-Alive)
return { status, headers, data };
};
Визуально:
Клиент (Браузер) Сервер
|
|--- TCP Connect ---------->|
|<------- TCP ACK ----------|
|
|--- SSL Handshake (HTTPS) ->|
|<-- SSL Handshake Response --|
|
|--- HTTP Request ---------->|
| (метод, URL, заголовки) |
| (тело запроса) |
|
|<-- HTTP Response ----------|
| (статус, заголовки) |
| (тело ответа) |
|
|--- TCP Close ------------>|
|<------- TCP FIN -----------|
2. HTTP методы (CRUD операции)
const httpMethods = {
// GET - получить данные (безопасен, кэшируется)
get: async () => {
const user = await fetch('/api/users/123').then(r => r.json());
// Можно кэшировать, безопасен, нет побочных эффектов
},
// POST - создать ресурс (изменяет состояние)
post: async () => {
const newUser = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'John', email: 'j@e.com' })
}).then(r => r.json());
// Каждый вызов создаёт новый ресурс
},
// PUT - заменить ресурс полностью (идемпотентен)
put: async () => {
const updated = await fetch('/api/users/123', {
method: 'PUT',
body: JSON.stringify({ name: 'Jane', email: 'j@e.com' })
}).then(r => r.json());
// Множественные вызовы = одинаковый результат
},
// PATCH - частичное обновление
patch: async () => {
const updated = await fetch('/api/users/123', {
method: 'PATCH',
body: JSON.stringify({ name: 'Jane' }) // только что менять
}).then(r => r.json());
},
// DELETE - удалить ресурс (идемпотентен)
delete: async () => {
const status = await fetch('/api/users/123', {
method: 'DELETE'
}).then(r => r.status);
// Второй вызов тоже вернёт 204 или 404
}
};
// Правило: GET/PUT/DELETE идемпотентны (повторяемы)
// POST - не идемпотентен (каждый вызов = новый результат)
3. HTTP статус-коды
const statusCodes = {
// 2xx - успех
'200': 'OK - запрос успешен',
'201': 'Created - ресурс создан (обычно POST)',
'204': 'No Content - успех, но нет тела ответа (DELETE)',
'206': 'Partial Content - часть контента (диапазоны)',
// 3xx - редирект
'300': 'Multiple Choices - несколько вариантов',
'301': 'Moved Permanently - постоянный редирект',
'302': 'Found - временный редирект',
'304': 'Not Modified - кэш актуален',
'307': 'Temporary Redirect - как 302, но сохраняет метод',
// 4xx - ошибка клиента
'400': 'Bad Request - неверный синтаксис',
'401': 'Unauthorized - нужна аутентификация',
'403': 'Forbidden - доступ запрещён',
'404': 'Not Found - ресурс не найден',
'408': 'Request Timeout - время ожидания истекло',
'429': 'Too Many Requests - rate limit',
// 5xx - ошибка сервера
'500': 'Internal Server Error - что-то сломалось',
'502': 'Bad Gateway - неверный ответ от upstream',
'503': 'Service Unavailable - сервер перегружен',
'504': 'Gateway Timeout - время ожидания от upstream'
};
// На фронтенде обрабатываем так:
const handleResponse = async (response) => {
if (response.ok) {
// 2xx - успех
return response.json();
} else if (response.status === 401) {
// Не авторизирован - редирект на логин
window.location.href = '/login';
} else if (response.status === 429) {
// Rate limit - показываем пользователю
throw new Error('Слишком много запросов, подождите');
} else if (response.status >= 500) {
// Ошибка сервера - retry
throw new Error('Сервер недоступен');
}
};
4. HTTP заголовки (Headers)
const httpHeaders = {
// Основные заголовки запроса
request: {
'Content-Type': 'application/json', // тип тела запроса
'Accept': 'application/json', // какой формат хотим
'Authorization': 'Bearer token123', // токен
'User-Agent': 'Mozilla/5.0...', // браузер
'Accept-Language': 'en-US', // предпочитаемый язык
'Cache-Control': 'no-cache', // кэширование
'Cookie': 'sessionId=abc123', // куки
'Origin': 'https://example.com', // откуда запрос (CORS)
'Referer': 'https://example.com/page' // откуда пришли
},
// Основные заголовки ответа
response: {
'Content-Type': 'application/json', // тип тела ответа
'Content-Length': '1234', // размер тела
'Cache-Control': 'max-age=3600', // кэш на 1 час
'Set-Cookie': 'sessionId=xyz789; Path=/', // установить куки
'Location': 'https://example.com/new', // редирект URL
'ETag': '"w/123abc"', // версия ресурса
'Last-Modified': 'Mon, 01 Jan 2024', // когда изменён
'Access-Control-Allow-Origin': '*', // CORS разрешение
'Access-Control-Allow-Methods': 'GET, POST', // какие методы
'Access-Control-Allow-Headers': 'Content-Type', // какие заголовки
'X-RateLimit-Remaining': '99', // сколько запросов осталось
'X-RateLimit-Reset': '1704067200' // когда сбросится
}
};
// Практический пример
const makeRequest = async () => {
const response = await fetch('/api/data', {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`
}
});
// Читаем важные заголовки ответа
const cacheControl = response.headers.get('Cache-Control');
const rateLimit = response.headers.get('X-RateLimit-Remaining');
const etag = response.headers.get('ETag');
return response.json();
};
5. Кэширование HTTP
// Cache-Control направляет браузер как кэшировать
const caching = {
// Не кэшировать (для данных, которые всегда меняются)
'no-cache, no-store': `
Браузер не кэширует
Каждый раз свежий запрос
`,
// Кэшировать на время
'max-age=3600': `
Браузер кэширует на 3600 секунд (1 час)
Если просишь опять в течение часа - вернёт из кэша
`,
// Стратегия переопроверки
'must-revalidate': `
Кэш истёк? Обязательно проверить на сервере
`,
// Для статических ресурсов
'public, max-age=31536000': `
Публичный кэш (CDN, прокси) на 1 год
Хорош для файлов с версиями в имени
`
};
// ETag и Last-Modified для проверки изменений
const handleCache = async () => {
// Первый запрос
let response = await fetch('/api/data');
const etag = response.headers.get('ETag');
const data = await response.json();
// Второй запрос с ETag
response = await fetch('/api/data', {
headers: {
'If-None-Match': etag // "если не изменился"
}
});
if (response.status === 304) {
// Not Modified - используй старые данные
console.log('Данные не изменились');
} else {
// Данные изменились
const newData = await response.json();
}
};
6. Persistent connections и HTTP/2
const httpVersions = {
// HTTP/1.1 (2009) - по умолчанию до недавна
'HTTP/1.1': {
keepAlive: 'Переиспользует одно соединение для нескольких запросов',
lineOfSight: 'Запросы идут по очереди (Head of Line Blocking)',
performance: 'Многие маленькие запросы = медленно'
},
// HTTP/2 (2015) - мультиплексирование
'HTTP/2': {
multiplexing: 'Множество запросов в одном соединении параллельно',
binaryProtocol: 'Бинарный формат вместо текста (быстрее)',
serverPush: 'Сервер может отправить ресурсы без запроса',
headerCompression: 'Заголовки сжимаются (HPACK)',
performance: 'Много маленьких запросов = быстро'
},
// HTTP/3 (2022) - на QUIC
'HTTP/3': {
quic: 'Использует QUIC вместо TCP',
faster: 'Быстрее переподключение (мобильные)',
noCongestion: 'Нет head-of-line blocking даже при потере пакетов'
}
};
// На практике
const checkVersion = async () => {
const response = await fetch('/api/data');
// response.type даст информацию, но версию HTTP не видно прямо
console.log('Браузер автоматически использует лучшую версию');
};
7. CORS (Cross-Origin Resource Sharing)
// Когда фронт (example.com) делает запрос к API (api.example.com)
const corsRequest = async () => {
// Браузер автоматически отправляет Origin
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
// Браузер добавляет: 'Origin': 'https://example.com'
},
body: JSON.stringify({})
});
// Сервер проверяет Access-Control-Allow-Origin
// Если не совпадает - браузер блокирует ответ (CORS error)
};
const handleCORS = () => {
// ✓ Сервер разрешил (предпродакшн)
const corsHeader = 'Access-Control-Allow-Origin: https://example.com';
// ❌ Сервер заблокировал (безопасность)
// Access-Control-Allow-Origin: https://other.com
// Браузер скроет ответ: "CORS policy blocked"
};
8. Производительность HTTP
const performanceTips = {
// 1. Минимизируй количество запросов
bundling: {
wrong: '100 маленьких файлов = 100 запросов',
right: 'Объедини в бандлы = 5 запросов',
tool: 'Webpack, Vite автоматически это делают'
},
// 2. Используй кэширование
caching: {
static: 'Картинки, CSS, JS - кэширование на год',
api: 'API данные - кэширование на 5-10 минут'
},
// 3. Сжатие (Gzip, Brotli)
compression: {
wrong: 'Отправляем 500KB JSON',
right: 'Сжимаем до 50KB Gzip',
header: 'Accept-Encoding: gzip, deflate, br'
},
// 4. CDN для географического распределения
cdn: {
what: 'Копируем статические файлы на серверы по миру',
benefit: 'Пользователь получает из ближайшего сервера'
},
// 5. Ленивая загрузка
lazy: {
images: 'Загружаем только видимые изображения',
api: 'Запрашиваем только нужные данные'
}
};
// Мониторим в браузере
const monitorHTTP = () => {
// DevTools -> Network tab -> всё видно
// Или programmatically
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') {
console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
}
}
});
observer.observe({ entryTypes: ['resource'] });
};
9. Обработка ошибок в HTTP
const errorHandling = async () => {
try {
const response = await fetch('/api/users/123');
// Проверяем статус
if (!response.ok) {
const error = await response.json();
throw new Error(`HTTP ${response.status}: ${error.message}`);
}
return await response.json();
} catch (error) {
if (error instanceof TypeError) {
// Сетевая ошибка (нет интернета, сервер недоступен)
console.error('Сетевая ошибка:', error);
} else if (error instanceof SyntaxError) {
// Ответ не JSON
console.error('Невалидный JSON:', error);
} else {
// Другая ошибка (включая HTTP ошибки)
console.error('Ошибка:', error);
}
}
};
// Retry logic
const fetchWithRetry = async (url, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, { timeout: 5000 });
if (response.ok) return response;
if (response.status >= 500) {
throw new Error('Server error'); // retry
}
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // exponential backoff
await new Promise(r => setTimeout(r, delay));
}
}
};
Итог: как работает HTTP
- Клиент отправляет запрос (метод, URL, заголовки, тело)
- Сервер обрабатывает и отправляет ответ (статус, заголовки, тело)
- Браузер обрабатывает ответ и рендерит страницу
- Кэширование экономит время и трафик
- HTTP/2 делает множество запросов быстрым
- Обработка ошибок важна для UX
Это основание всей веб-разработки.