Отправить запрос с сайта на сервер

Хотите отправить запрос с сайта на сервер без головной боли? Разбираемся вместе: понятные примеры, живой код и никакой занудной теории!

Бесплатная консультация юриста

+7 (800) 302-87-29

Реклама jurik.ru

Взаимодействие клиентской части (фронтенда) с серверной (бэкендом) — это фундамент современной веб-разработки․ Процесс отправки запроса с сайта на сервер включает в себя несколько этапов: формирование данных, выбор протокола и метода, обработка ответа и работа с ошибками․ В этой статье мы подробно разберем, как это работает на стороне браузера (клиент) и на стороне сервера (Node․js), опираясь на современные стандарты и популярные инструменты․

Основы HTTP-взаимодействия

Прежде чем писать код, важно понимать базовые понятия․ Обмен данными в вебе происходит по протоколу HTTP/HTTPS․ Каждый запрос состоит из:

  • Метода (глагола): определяет действие (GET, POST, PUT, PATCH, DELETE)․
  • URL (эндпоинта): адрес ресурса на сервере․
  • Заголовков (Headers): метаданные (тип контента, авторизация, кэширование)․
  • Тела (Body): полезная нагрузка (обычно JSON, FormData или бинарные данные), передается при POST/PUT/PATCH․

Основные HTTP-методы

Метод Назначение Тело запроса Идемпотентность
GET Получение данных Нет Да
POST Создание нового ресурса Да Нет
PUT Полное обновление ресурса Да Да
PATCH Частичное обновление ресурса Да Нет
DELETE Удаление ресурса Редко Да

Часть 1: Клиентская сторона (Браузер / Frontend)

В браузере есть два основных API для выполнения сетевых запросов: старый XMLHttpRequest (устарел, но встречается в легаси) и современный Fetch API․ Также широко используются сторонние библиотеки, такие как Axios․

Fetch API (Стандарт браузера)

fetch — это глобальная функция, возвращающая Promise․ Она доступна во всех современных браузерах без установки пакетов․

Базовый GET-запрос

async function loadUsers {
 try {
 const response = await fetch('https://jsonplaceholder․typicode․com/users');
 
 // fetch не выбрасывает ошибку при HTTP-статусах 4xx/5xx, нужно проверять response․ok
 if (!response․ok) {
 throw new Error(`Ошибка HTTP: ${response․status}`);
 }
 
 const users = await response․json;
 console․log(users);
 } catch (error) {
 console․error('Ошибка загрузки:', error);
 }
}

loadUsers;

POST-запрос с отправкой JSON

async function createUser(userData) {
 try {
 const response = await fetch('https://jsonplaceholder․typicode․com/users', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json', // Важно указывать тип контента
 },
 body: JSON․stringify(userData), // Превращаем объект в JSON-строку
 });
 if (!response․ok) throw new Error('Не удалось создать пользователя');
 
 const newUser = await response․json;
 console․log('Создан:', newUser);
 } catch (error) {
 console․error(error);
 }
}

createUser({ name: 'Иван', email: 'ivan@example․com' });

Отправка формы (FormData)

Если сервер ожидает multipart/form-data (например, загрузка файлов), не нужно устанавливать заголовок Content-Type вручную — браузер сделает это сам с правильной границей (boundary)․

const form = document․getElementById('myForm');
form․addEventListener('submit', async (e) => {
 e․preventDefault;
 const formData = new FormData(form); // Автоматически собирает данные из input
 
 const response = await fetch('/api/upload', {
 method: 'POST',
 body: formData,
 });
 
 const result = await response․json;
 alert('Файл загружен!');
});

Axios (Популярная библиотека)

Axios устанавливается через npm/yarn/pnpm: npm install axios․ Он работает и в браузере, и в Node․js․

Преимущества Axios:

  • Автоматическое преобразование JSON (не нужно вызывать ․json)․
  • Обработка ошибок: выбрасывает исключение при статусах 4xx/5xx․
  • Поддержка интерцепторов (перехватчиков) для добавления токенов авторизации․
  • Защита от XSRF на клиенте․
  • Удобная отмена запросов (AbortController / CancelToken)․

Примеры с Axios

import axios from 'axios';

// Создаем экземпляр с базовым URL (Best Practice)
const api = axios․create({
 baseURL: 'https://api․example․com',
 timeout: 5000, // Таймаут 5 секунд
 headers: { 'X-Custom-Header': 'value' }
});

// Интерцептор для добавления токена к каждому запросу
api․interceptors․request․use(config => {
 const token = localStorage․getItem('authToken');
 if (token) config․headers․Authorization = `Bearer ${token}`;
 return config;
});
// GET
async function getUsers {
 try {
 const response = await api․get('/users'); // Данные в response․data
 console․log(response․data);
 } catch (error) {
 handleApiError(error);
 }
}

// POST
async function createPost(title, body) {
 try {
 const response = await api;post('/posts', { title, body });
 console․log('Создано:', response․data);
 } catch (error) {
 handleApiError(error);
 }}

function handleApiError(error) {
 if (error․response) {
 // Сервер ответил с кодом ошибки (4xx, 5xx)
 console․error('Статус:', error․response․status);
 console․error('Данные ошибки:', error․response․data);
 } else if (error․request) {
 // Запрос ушел, ответа нет (сеть, CORS, таймаут)
 console․error('Нет ответа от сервера');
 } else {
 // Ошибка настройки запроса
 console․error('Ошибка:', error․message);
 }
}

Работа с аутентификацией и Cookies

По умолчанию fetch не отправляет и не принимает cookies (включая HttpOnly) при кросс-доменных запросах․ Для этого нужно явно указать credentials: 'include'․

// Fetch с куками
fetch('https://api․another-domain․com/profile', {
 method: 'GET',
 credentials: 'include' // Важно для отправки/приема cookies
});

// Axios (настройка withCredentials)
axios․get('https://api․another-domain․com/profile', {
 withCredentials: true
});

Важно: Сервер должен ответить заголовком Access-Control-Allow-Credentials: true и конкретным Access-Control-Allow-Origin (не *), иначе браузер заблокирует ответ (CORS policy)․


Часть 2: Серверная сторона (Node․js / Backend)

Часто возникает необходимость отправить запрос с сервера на другой сервер (микросервисы, интеграция с платежными шлюзами, внешние API)․ Начиная с Node․js 18, Fetch API доступен глобально без установки зависимостей․ Для старых версий (v16, v14) используется пакет node-fetch или нативный модуль https․

Нативный Fetch (Node․js 18+)

Синтаксис идентичен браузерному, но есть нюансы: нет объекта window, нет FormData (до Node 18/20 требовался полифилл), другие ошибки сети․

GET запрос с TypeScript

// Типизация ответа
interface ApiResponse {
 id: number;
 name: string;
 email: string;
}

async function fetchUserData: Promise<ApiResponse | null> {
 try {
 const response = await fetch('https://jsonplaceholder․typicode․com/users/1');
 
 if (!response․ok) {
 // В Node;js fetch не бросает ошибку на 404/500
 throw new Error(`HTTP Error: ${response․status} ${response․statusText}`);
 }
 
 const data: ApiResponse = await response․json;
 return data;
 } catch (error) {
 console․error('Ошибка при запросе к внешнему API:', error);
 return null;
 }
}

POST запрос с JSON

async function sendNotification(webhookUrl: string, payload: object) {
 try {
 const response = await fetch(webhookUrl, {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 'User-Agent': 'MyApp/1․0' // Хорошая практика указывать User-Agent
 },
 body: JSON․stringify(payload),
 // Node․js специфичные опции (не работают в браузере):
 // agent: new https․Agent({ keepAlive: true }), // Пулинг соединений
 // timeout: 5000 // В нативном fetch пока нет таймаута, нужна AbortController
 });

 if (!response․ok) {
 const errorText = await response․text;
 throw new Error(`Webhook failed: ${response․status} ⎻ ${errorText}`);
 }
 
 return await response․json;
 } catch (error) {
 // Обработка сетевых ошибок (ENOTFOUND, ECONNREFUSED, ETIMEDOUT)
 console․error('Сетевая ошибка:', error․code || error․message);
 throw error; // Пробрасываем выше для ретраев или логирования
 }}

Axios в Node․js

Axios остается популярным выбором для бэкенда благодаря удобству, встроенным таймаутам и автоматической сериализации․

// npm install axios
import axios from 'axios';


// Создание клиента с базовыми настройками (Best Practice для микросервисов)
const httpClient = axios․create({
 baseURL: 'https://api․payment-gateway․com/v1',
 timeout: 10000, // 10 секунд таймаут (работает из коробки!)
 headers: {
 'Authorization': `Bearer ${process․env․PAYMENT_API_KEY}`,
 'Idempotency-Key': crypto․randomUUID // Защита от двойных списаний
 }
});

// POST запрос
async function chargeCustomer(amount: number, currency: string) {
 try {
 const response = await httpClient․post('/charges', {
 amount,
 currency,
 source: 'token_from_client'
 });
  // Axios всегда возвращает данные в response;data
 return response․data; 
 } catch (error) {
 if (axios․isAxiosError(error)) {
 // Типизированная ошибка Axios
 if (error․response) {
 // Ответ получен, но статус 4xx/5xx
 throw new PaymentError(error․response․data․message, error․response․status);
 } else if (error․request) {
 // Таймаут или нет связи
 throw new NetworkError('Платежный шлюз недоступен');
 } } throw error;
 }}

Нативный модуль https (Без зависимостей, низкий уровень)

Используется, если нельзя установить пакеты (например, в AWS Lambda слоях без node_modules или для максимальной производительности/контроля)․ Работает на колбэках/промисах вручную․

import https from 'https';

function postJson(url: string, data: object): Promise<any> {
 return new Promise((resolve, reject) => {
 const postData = JSON․stringify(data);
 const parsedUrl = new URL(url);
 
 const options = {
 hostname: parsedUrl․hostname,
 port: parsedUrl․port || 443,
 path: parsedUrl․pathname + parsedUrl;search,
 method: 'POST',
 headers: {
 'Content-Type': 'application/json',
 'Content-Length': Buffer․byteLength(postData)
 },
 timeout: 5000 // Таймаут на сокете
 };

 const req = https․request(options, (res) => {
 let rawData = '';
 res․on('data', (chunk) => { rawData += chunk; });
 res․on('end',  => {
 try {
 const parsed = JSON․parse(rawData);
 if (res․statusCode && res․statusCode >= 400) {
 reject(new Error(`HTTP ${res․statusCode}: ${parsed․message || rawData}`));
 } else {
 resolve(parsed);
 }
 } catch (e) {
 reject(new Error('Invalid JSON response'));
 }
 });
 });
 req․on('error', (e) => reject(e));
 req․on('timeout',  => { req․destroy; reject(new Error('Request timeout')); });
 
 req․write(postData);
 req․end;
 });
}

Часть 3: Лучшие практики и безопасность

Обработка ошибок и Retry-стратегии

Сетевые запросы могут падать по множеству причин․ На бэкенде критически важно реализовывать повторные попытки (retry) с экспоненциальной задержкой (exponential backoff) для идемпотентных операций (GET, PUT, DELETE)․

// Пример утилиты для ретраев (упрощенно)
async function fetchWithRetry(url, options, retries = 3, delay = 1000) {
 try {
 return await fetch(url, options);
 } catch (error) {
 if (retries === 0) throw error;
 // Ждем перед следующей попыткой
 await new Promise(r => setTimeout(r, delay));
 return fetchWithRetry(url, options, retries ⎻ 1, delay * 2);
 }
}

Таймауты (Timeouts)

  • Браузер:
    Используйте AbortController․
  • Node․js (fetch): const controller = new AbortController; setTimeout( => controller․abort, 5000); fetch(url, { signal: controller․signal })․
  • Axios: Встроенная опция timeout: 5000․

Безопасность (Security)

  • HTTPS Only: Никогда не отправляйте чувствительные данные по HTTP․
  • Валидация SSL: В Node․js по умолчанию проверяются сертификаты․ Отключение (rejectUnauthorized: false) — критическая уязвимость (MITM)․
  • Секреты в коде: Не хардкодьте API-ключи․ Используйте переменные окружения (process․env)․
  • CORS: Настраивайте на сервере строго: разрешайте только нужные домены, методы и заголовки․
  • Rate Limiting: Защищайте свои эндпоинты от DDoS и брутфорса лимитерами запросов․

Производительность

  • Connection Pooling (Keep-Alive): В Node․js используйте agent: new http․Agent({ keepAlive: true }) или настройку Axios для переиспользования TCP-соединений при частых запросах к одному хосту․
  • Сжатие: Убедитесь, что клиент отправляет Accept-Encoding: gzip, deflate, br, а сервер сжимает ответы․
  • Кэширование: Используйте заголовки ETag, If-None-Match, Cache-Control для GET-запросов․

Сравнительная таблица: Что выбрать?

Инструмент Среда Плюсы Минусы Когда использовать
Fetch API Браузер, Node 18+ Стандарт, без зависимостей, Promise-based, Streaming Нет таймаутов «из коробки», не бросает ошибку на 4xx/5xx, verbose для простых задач Современные проекты без лишних зависимостей, Edge Runtime (Cloudflare Workers, Vercel Edge)
Axios Браузер, Node․js Интерцепторы, таймауты, авто-JSON, отмена запросов, XSRF защита, широкая поддержка TS Внешняя зависимость (~50kb gzip), класс-обертка (не стандарт Web API) Сложные приложения, нужна централизованная обработка ошибок/авторизации, работа с FormData/потоками
Node https/http Только Node․js Нет зависимостей, полный контроль, максимальная скорость, стриминг Низкий уровень, ручное управление промисами/буферами, нет редиректов, нет пулинга по умолчанию Serverless функции с лимитом размера, высоконагруженные прокси, легаси Node < 18
Ky / Got Браузер / Node․js Легкие, современные обертки над Fetch, удобный синтаксис, хуки, ретраи встроены Зависимости (маленькие), менее известны, чем Axios Альтернатива Axios, если нужен стандарт Fetch, но с удобным API

Отправка запроса с сайта на сервер — задача, которая решается по-разному в зависимости от контекста:

  1. На фронтенде (Браузер): Стандартом де-факто является Fetch API для простых задач и Axios для сложных приложений с требованием к интерцепторам и удобной обработке ошибок․
  2. На бэкенде (Node․js): Начиная с версии 18, нативный Fetch стал полноценным конкурентом библиотекам․ Axios остается отличным выбором за счет встроенных таймаутов и удобства․ Для высоконагруженных систем без зависимостей — нативный модуль https․

Ключевые принципы надежной интеграции: всегда проверяйте response․ok / статус код, используйте таймауты, логируйте ошибки с контекстом и храните секреты в переменных окружения․ Правильная архитектура сетевого слоя сэкономит часы отладки в продакшене․