В чем заключается механизм CORS и какую проблему он решает?

Ответ

CORS (Cross-Origin Resource Sharing) — это механизм безопасности, встроенный в браузеры, который позволяет веб-странице запрашивать ресурсы с другого домена (origin), отличного от того, с которого она была загружена.

Проблема, которую решает CORS

По умолчанию в браузерах действует политика одинакового источника (Same-Origin Policy, SOP), которая запрещает скриптам с одного сайта получать доступ к данным на другом. Это защищает пользователей от вредоносных сайтов, которые могли бы читать данные из вашей почты или банковского аккаунта, открытых в соседних вкладках.

CORS предоставляет серверу контролируемый способ "ослабить" эту политику и разрешить доверенным сайтам получать доступ к его ресурсам.

Как это работает?

Когда фронтенд (например, с https://my-app.com) пытается отправить "сложный" запрос (например, PUT или с кастомными заголовками) к API на https://api.service.com, браузер автоматически выполняет preflight-запрос (предварительный запрос) с методом OPTIONS.

Сервер должен ответить, разрешает ли он такой запрос, отправив специальные HTTP-заголовки:

  • Access-Control-Allow-Origin: Указывает, каким доменам разрешен доступ (https://my-app.com или * для всех).
  • Access-Control-Allow-Methods: Список разрешенных методов (GET, POST, DELETE и т.д.).
  • Access-Control-Allow-Headers: Список разрешенных заголовков запроса.

Если ответ сервера разрешающий, браузер отправляет основной запрос. В противном случае — блокирует его.

Пример на Flask с использованием flask-cors (best practice):

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

# Разрешить запросы с домена 'https://my-app.com' для всех роутов, начинающихся с /api/
CORS(app, resources={r"/api/*": {"origins": "https://my-app.com"}})

@app.route('/api/data')
def get_data():
    return jsonify({'message': 'This is cross-origin data!'})

Ответ 18+ 🔞

Так, слушай, а вот есть у нас такая хуйня в браузерах — CORS. Это, блядь, не просто так, это защита, чтобы какой-нибудь левый сайт не мог слить твою почту или банковские данные, пока ты в другой вкладке сидишь. По умолчанию браузер — он как строгий отец: «С какого хуя ты лезешь на чужой домен? Нельзя!». Это политика одинакового источника, SOP называется.

Но иногда нам надо, понимаешь? Фронтенд на my-app.com хочет стянуть данные с API на api.service.com. Вот тут CORS и включается. Это такой контролируемый способ сказать браузеру: «Эй, расслабься, я этого чувака знаю, пусть берёт».

А теперь самое весёлое. Когда твой скрипт пытается отправить не простой запрос (не GET или POST с обычными заголовками), а какой-нибудь замудрённый — с методом PUT или кастомными заголовками, — браузер, этот дотошный пидорас, сначала шлёт предварительный запрос (preflight) методом `OPTIONS**. Типа: «Эй, сервак, а можно так-то?».

И сервер должен ответить правильно, а то пиздец. Он шлёт заголовки:

  • Access-Control-Allow-Origin: с какого домена можно (например, https://my-app.com или звёздочка * — но это, блядь, как дверь нараспашку, осторожно).
  • Access-Control-Allow-Methods: какие методы разрешены (GET, POST, DELETE — весь список).
  • Access-Control-Allow-Headers: какие заголовки в запросе можно использовать.

Если сервер ответил «да, вали, братан», браузер отпускает основной запрос. Если нет — просто блокирует его, и ты в консоли видишь эту ёбаную ошибку, от которой волосы дыбом встают.

Вот как это по-человечески на Flask делается (с расширением flask-cors, ибо самому всё это прописывать — тот ещё геморрой):

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)

# Разрешаем запросы только с 'https://my-app.com' и только для роутов, которые начинаются с /api/
# Чтобы не открывать всё нараспашку, как последнему распиздю.
CORS(app, resources={r"/api/*": {"origins": "https://my-app.com"}})

@app.route('/api/data')
def get_data():
    return jsonify({'message': 'This is cross-origin data!'})

Вот и вся магия. Главное — не забыть на сервере эти заголовки правильно выставить, а то будет «ошибка CORS», и ты полдня будешь искать, в чём же, блядь, дело.