← Назад к вопросам

Что нужно сделать на клиентской части для запроса с одного сайта к другому?

2.3 Middle🔥 191 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Запросы между доменами (CORS): клиентская часть

Когда фронтенд-приложение на одном домене делает запрос к API на другом домене, это называется cross-origin request (кросс-доменный запрос). Браузер защищает такие запросы с помощью CORS (Cross-Origin Resource Sharing) политики. На клиентской стороне требуется понимание этого механизма и правильная конфигурация.

Основное понятие: Same-Origin Policy

Браузер по умолчанию разрешает запросы только с одного источника (Origin). Origin состоит из схемы, домена и порта:

https://example.com:443 (Origin)
      |
      ├- Схема: https://
      ├- Домен: example.com
      └- Порт: 443

Same Origin (разрешено):

Cross Origin (запрещено без CORS):

CORS Prelight запрос

Для "сложных" запросов браузер автоматически отправляет prefligh запрос OPTIONS перед основным запросом:

fetch('https://api.other-domain.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Custom-Header': 'value'
  },
  body: JSON.stringify({ name: 'Alice' })
});

// Браузер сначала отправляет OPTIONS запрос:
// OPTIONS /data HTTP/1.1
// Origin: https://example.com
// Access-Control-Request-Method: POST
// Access-Control-Request-Headers: Content-Type, Custom-Header
//
// Если сервер разрешит, тогда отправляется основной POST запрос

Простые vs Сложные запросы

Простые запросы (Simple Requests) - не требуют prefligh:

// GET запросы
fetch('https://api.other-domain.com/data')

// POST с текстом
fetch('https://api.other-domain.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain'
  },
  body: 'simple text'
})

// HEAD запросы
fetch('https://api.other-domain.com/data', {
  method: 'HEAD'
})

Сложные запросы (Complex Requests) - требуют prefligh:

// POST с JSON
fetch('https://api.other-domain.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Alice' })
})

// PUT, DELETE, PATCH
fetch('https://api.other-domain.com/data/123', {
  method: 'DELETE'
})

// С пользовательскими заголовками
fetch('https://api.other-domain.com/data', {
  headers: {
    'X-Custom-Header': 'value'
  }
})

// С credentials
fetch('https://api.other-domain.com/data', {
  credentials: 'include'
})

Что клиент может сделать

1. Отправить запрос с указанием credentials

// Отправлять cookies с запросом
fetch('https://api.other-domain.com/data', {
  method: 'GET',
  credentials: 'include', // Отправляет cookies
  headers: {
    'Authorization': 'Bearer token123'
  }
});

// Варианты credentials:
// 'omit' - не отправлять cookies (по умолчанию)
// 'same-origin' - отправлять только для same-origin
// 'include' - отправлять всегда (требует правильные CORS заголовки)

2. Установить правильные заголовки

fetch('https://api.other-domain.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token123',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    name: 'Alice',
    email: 'alice@example.com'
  })
})
.then(response => {
  if (!response.ok) throw new Error('Network response was not ok');
  return response.json();
})
.catch(error => {
  console.error('CORS error:', error);
});

3. Использовать axios с конфигурацией CORS

import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: 'https://api.other-domain.com',
  headers: {
    'Content-Type': 'application/json'
  },
  withCredentials: true // Эквивалент credentials: 'include'
});

axiosInstance.get('/data')
  .then(response => console.log(response.data))
  .catch(error => console.error('CORS error:', error));

4. Обработать CORS ошибку

fetch('https://api.other-domain.com/data')
  .then(response => {
    // CORS ошибка может быть перехвачена
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .catch(error => {
    // CORS ошибка будет здесь
    if (error instanceof TypeError) {
      console.error('CORS Error:', error.message);
      console.error('Check server CORS configuration');
    }
  });

5. Использовать JSONP как альтернатива (устаревший способ)

// JSONP - обходит CORS, но устаревший подход
const script = document.createElement('script');
script.src = 'https://api.other-domain.com/data?callback=handleData';
document.head.appendChild(script);

window.handleData = function(data) {
  console.log(data);
};

6. Использовать proxy на своем сервере

// Клиент запрашивает свой сервер
fetch('/api/proxy/data', {
  method: 'GET'
})
.then(res => res.json())
.then(data => console.log(data));

// Сервер (Node.js/Express)
app.get('/api/proxy/data', async (req, res) => {
  const response = await fetch('https://api.other-domain.com/data');
  const data = await response.json();
  res.json(data);
});

Практические примеры

1. GET запрос с API ключом

const API_KEY = 'your-api-key';
const API_URL = 'https://api.external-service.com';

fetch(`${API_URL}/users`, {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Accept': 'application/json'
  }
})
.then(res => res.json())
.then(data => console.log('Users:', data))
.catch(error => console.error('Error:', error));

2. POST запрос с JSON

fetch('https://api.external-service.com/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  credentials: 'include',
  body: JSON.stringify({
    email: 'user@example.com',
    name: 'John Doe'
  })
})
.then(res => {
  if (res.status === 401) {
    throw new Error('Unauthorized');
  }
  return res.json();
})
.then(data => console.log('Success:', data))
.catch(error => {
  if (error instanceof TypeError) {
    console.error('CORS Error: ', error);
  } else {
    console.error('Error:', error.message);
  }
});

3. Обработка различных HTTP методов

const baseURL = 'https://api.other-domain.com';

// DELETE запрос
fetch(`${baseURL}/users/123`, {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer token'
  }
});

// PUT запрос
fetch(`${baseURL}/users/123`, {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ name: 'Updated Name' })
});

// PATCH запрос
fetch(`${baseURL}/users/123`, {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token'
  },
  body: JSON.stringify({ name: 'Updated Name' })
});

4. React пример с обработкой CORS

import { useState, useEffect } from 'react';

function ExternalDataFetch() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch('https://api.other-domain.com/data', {
          method: 'GET',
          headers: {
            'Accept': 'application/json',
            'Authorization': 'Bearer token123'
          },
          credentials: 'include'
        });

        if (!response.ok) {
          throw new Error('Failed to fetch data');
        }

        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
        console.error('CORS Error:', err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return <div>{JSON.stringify(data)}</div>;
}

Таблица: Требуемые заголовки

ЗаголовокНазначениеПример
OriginOrigin запроса (автоматический)Origin: https://example.com
AuthorizationАутентификацияAuthorization: Bearer token123
Content-TypeТип контентаContent-Type: application/json
AcceptЖелаемый формат ответаAccept: application/json
Custom-HeaderСвой заголовокX-API-Version: v1

Проверка CORS в браузере

// DevTools -> Network tab -> найти запрос
// Response Headers должны содержать:
// Access-Control-Allow-Origin: https://example.com
// Access-Control-Allow-Methods: GET, POST, PUT
// Access-Control-Allow-Headers: Content-Type, Authorization
// Access-Control-Allow-Credentials: true

// Если этих заголовков нет - сервер не настроен для CORS

Типичные CORS ошибки

Access to XMLHttpRequest at 'https://api.other.com/data' from origin 
'https://myapp.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

-> Решение: Сервер должен отправлять
   Access-Control-Allow-Origin: https://myapp.com

Access to XMLHttpRequest ... has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Expected 'true' in CORS header 'Access-Control-Allow-Credentials'.

-> Решение: Добавить withCredentials: true на клиенте
   и Access-Control-Allow-Credentials: true на сервере

Вывод

На клиентской стороне нужно:

  • Установить правильные заголовки (Content-Type, Authorization)
  • Использовать credentials: 'include' если нужны cookies
  • Обработать CORS ошибки
  • Использовать fetch API или axios

Но самое важное:

  • CORS настраивается на сервере, не на клиенте
  • Клиент может только правильно отправить запрос
  • Сервер должен отправить правильные CORS заголовки в ответе
  • Если CORS не работает - проблема в конфигурации сервера

Альтернативы:

  • Proxy на своем сервере
  • JSONP (устаревший способ)
  • WebSockets (для реал-тайма)
  • Same-domain архитектура
Что нужно сделать на клиентской части для запроса с одного сайта к другому? | PrepBro