Ответ
CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который позволяет веб-странице запрашивать ресурсы (например, API, шрифты, изображения) с домена, отличного от того, с которого была загружена сама страница.
Проблема, которую решает CORS
По умолчанию браузеры следуют политике одинакового источника (Same-Origin Policy, SOP), которая запрещает скриптам делать запросы к другому домену, протоколу или порту. Это защищает пользователей от вредоносных сайтов, которые могли бы читать данные с других открытых вкладок (например, из онлайн-банка).
CORS предоставляет серверам контролируемый способ ослабить эту политику и разрешить кросс-доменные запросы от доверенных источников.
Как работает CORS
- Простой запрос (например,
GETилиPOSTс простыми заголовками): браузер отправляет запрос, добавляя заголовокOriginс указанием домена-инициатора. - Ответ сервера: Если сервер разрешает запрос с этого домена, он возвращает ответ с заголовком
Access-Control-Allow-Origin: <домен>илиAccess-Control-Allow-Origin: *(разрешить всем). - Предварительный запрос (Preflight Request): для "сложных" запросов (например, с методами
PUT,DELETEили нестандартными заголовками) браузер сначала отправляетOPTIONS-запрос на тот же URL.- Сервер в ответ должен прислать заголовки, разрешающие метод, заголовки и источник (
Access-Control-Allow-Methods,Access-Control-Allow-Headers). - Если preflight-запрос успешен, браузер отправляет основной запрос.
- Сервер в ответ должен прислать заголовки, разрешающие метод, заголовки и источник (
Пример настройки CORS в FastAPI (Python)
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Список доменов, которым разрешены запросы
origins = [
"http://localhost:3000",
"https://my-frontend-app.com",
]
# Добавление middleware для обработки CORS
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # Разрешенные домены
allow_credentials=True, # Разрешить cookies
allow_methods=["GET", "POST"], # Разрешенные HTTP-методы
allow_headers=["Authorization"], # Разрешенные HTTP-заголовки
)
@app.get("/api/data")
def get_data():
return {"message": "This data is accessible via CORS"}
Если браузер не получит нужные заголовки от сервера, он заблокирует ответ, и в консоли разработчика появится ошибка CORS.
Ответ 18+ 🔞
О, слушай, вот тебе история про одну ебанутую защиту в браузерах, которая всех бесит, но на самом деле она нас спасает. Зовут её CORS, а расшифровывается как «Cross-Origin Resource Sharing», но всем похуй, главное — что она делает.
Представь себе, ты сидишь на сайте pornhub.com (ну, для примера). И твоя страничка, такая хитрая жопа, решает: «А не сходить ли мне на my-bank.com и не стырить ли данные пользователя?». Так вот, чтобы этого не случилось, браузеры придумали политику одинакового источника (Same-Origin Policy, SOP). Это такой злой батя, который говорит: «Нихуя, сынок, с этого домена — только на этот домен. Не лезь, куда не просят».
Но иногда нам, разработчикам, реально надо сделать запрос на другой домен — например, наш фронтенд на localhost:3000 хочет поговорить с бэкендом на localhost:8000. Вот тут-то и появляется наш «спаситель» — CORS. Это не отмена правил, а такой официальный пропуск, который сервер может выдать.
Как эта хуйня работает, по шагам:
- Твой скрипт пытается отправить запрос куда-то не туда. Браузер, такой бдительный страж, прикрепляет к запросу заголовок
Origin: http://твой-сайт.com. - Сервер получает запрос и решает: «А, этот чувак с того домена... Ну, окей, пусть». И в ответе он добавляет волшебный заголовок:
Access-Control-Allow-Origin: http://твой-сайт.com(или звёздочку*, если он похуист и пускает всех). - Браузер видит этот заголовок и говорит: «Ну ладно, раз сервер разрешил — проходи». И отдаёт ответ твоему скрипту.
Но это ещё цветочки! Бывают сложные запросы — не GET или POST, а всякие PUT, DELETE, или с какими-то нестандартными заголовками вроде Authorization. Тут браузер вообще параноиком становится и делает предварительный запрос (Preflight).
Он сначала шлёт запрос методом OPTIONS (типа «эй, сервак, а можно так?»), и ждёт, чтобы сервер ответил: «Да, можно метод PUT, да, можно заголовок X-My-Header, и вообще заходи». И только после этого, ебать, отправляет настоящий запрос. Если сервер на OPTIONS не ответил как надо — всё, пиздец, основной запрос даже не уйдёт.
А вот как это настроить, например, на FastAPI, чтобы не орать потом «почему не работает, блядь?»:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Список доменов, которым разрешены запросы
origins = [
"http://localhost:3000",
"https://my-frontend-app.com",
]
# Добавление middleware для обработки CORS
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # Разрешенные домены
allow_credentials=True, # Разрешить cookies
allow_methods=["GET", "POST"], # Разрешенные HTTP-методы
allow_headers=["Authorization"], # Разрешенные HTTP-заголовки
)
@app.get("/api/data")
def get_data():
return {"message": "This data is accessible via CORS"}
Если ты всё настроил, а в консоли браузера всё равно красуется ошибка про CORS — значит, сервер нихуя не разрешил. Либо домен не тот, либо метод, либо заголовки. Волнение ебать, но надо просто проверить, что сервер шлёт в ответах на твои запросы. Вот и вся магия, ёпта.