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

Зачем нужен запрос OPTIONS в http?

2.0 Middle🔥 161 комментариев
#REST API и HTTP

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

Зачем нужен запрос OPTIONS в HTTP?

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

Основное назначение OPTIONS

OPTIONS запрос позволяет клиенту узнать, какие методы доступны для определённого ресурса, какие заголовки поддерживаются и другие параметры коммуникации.

# Пример обработки OPTIONS в FastAPI
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# CORS уже обрабатывает OPTIONS автоматически
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Но можно обработать OPTIONS вручную
@app.options("/api/users")
async def preflight_users():
    return {
        "allowed_methods": ["GET", "POST", "OPTIONS"],
        "allowed_headers": ["Content-Type", "Authorization"],
        "allowed_origins": ["*"],
        "max_age": 3600  # Кэшировать результат на 1 час
    }

Два основных применения

1. CORS Preflight запрос

Это самое частое использование OPTIONS. Когда браузер делает cross-origin запрос определённого типа, он сначала отправляет OPTIONS запрос (preflight) для проверки прав доступа.

# Браузер на example.com отправляет запрос к api.other.com
# Процесс:

# 1. Браузер отправляет preflight OPTIONS запрос
OPTIONS /api/users HTTP/1.1
Host: api.other.com
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

# 2. Сервер отвечает с разрешениями
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600

# 3. Если разрешено, браузер отправляет реальный запрос
POST /api/users HTTP/1.1
Host: api.other.com
Origin: https://example.com
Content-Type: application/json

Пример с Flask:

from flask import Flask, request
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # Автоматически обрабатывает OPTIONS

@app.route('/api/users', methods=['GET', 'POST', 'OPTIONS'])
def users():
    if request.method == 'OPTIONS':
        response = app.make_default_options_response()
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
        return response
    
    elif request.method == 'POST':
        # Обработка POST
        return {"message": "User created"}
    
    else:  # GET
        return {"users": []}

2. Получение доступных методов

Клиент может использовать OPTIONS для выяснения, какие методы поддерживает API.

# Запрос
OPTIONS * HTTP/1.1
Host: example.com

# Ответ
HTTP/1.1 200 OK
Allow: GET, HEAD, PUT, DELETE, OPTIONS
Accept-Ranges: bytes
Content-Length: 0

Когда браузер отправляет preflight OPTIONS запрос

Не для каждого запроса браузер отправляет preflight. OPTIONS отправляется только для "non-simple" запросов:

# Простые запросы (БЕЗ preflight):
# - GET, HEAD, POST
# - Стандартные headers: Accept, Accept-Language, Content-Language, Content-Type
# - Content-Type только: application/x-www-form-urlencoded, multipart/form-data, text/plain

# Сложные запросы (С preflight OPTIONS):

# 1. Метод: PUT, DELETE, PATCH
fetch('https://api.example.com/users/1', {
    method: 'PUT',  # Сложный метод
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: 'John'})
})
# Браузер отправит OPTIONS перед PUT

# 2. Custom headers
fetch('https://api.example.com/users', {
    method: 'GET',
    headers: {'X-Custom-Header': 'value'}  # Custom header
})
// OPTIONS будет отправлен

# 3. Content-Type: application/json
fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},  # Не simple
    body: JSON.stringify({name: 'John'})
})
// OPTIONS будет отправлен

Обработка OPTIONS в разных фреймворках

FastAPI с автоматической CORS

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com", "https://app.example.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["*"],
    max_age=600,  # Кэшировать preflight на 10 минут
)

@app.post("/api/users")
async def create_user(user_data: dict):
    return {"id": 1, "name": user_data["name"]}

# OPTIONS обрабатывается автоматически, нет нужды писать обработчик

Django с django-cors-headers

# settings.py
INSTALLED_APPS = [
    'corsheaders',
    # ...
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # ...
]

CORS_ALLOWED_ORIGINS = [
    "https://example.com",
    "https://app.example.com",
]

CORS_ALLOW_METHODS = [
    'GET',
    'POST',
    'PUT',
    'DELETE',
]

CORS_ALLOW_HEADERS = [
    'Content-Type',
    'Authorization',
]

# OPTIONS обрабатывается автоматически

Ручная обработка OPTIONS

from fastapi import FastAPI

app = FastAPI()

@app.options("/api/users/{user_id}")
async def options_user(user_id: int):
    return {
        "allowed_methods": ["GET", "PUT", "DELETE"],
        "allowed_headers": ["Content-Type", "Authorization"],
        "allowed_origins": ["*"],
    }

@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
    return {"id": user_id, "name": "John"}

@app.put("/api/users/{user_id}")
async def update_user(user_id: int, data: dict):
    return {"id": user_id, "updated": True}

@app.delete("/api/users/{user_id}")
async def delete_user(user_id: int):
    return {"deleted": True}

Оптимизация OPTIONS запросов

1. Кэширование preflight

# Сервер сообщает браузеру кэшировать результат
Access-Control-Max-Age: 86400  # Кэшировать на 24 часа

# Браузер не будет отправлять OPTIONS для каждого запроса

2. Минимизация preflight запросов

# Плохо: 3 preflight запроса
fetch('/api/users', {method: 'POST', headers: {'X-Header': 'value'}})
fetch('/api/products', {method: 'POST', headers: {'X-Header': 'value'}})
fetch('/api/orders', {method: 'POST', headers: {'X-Header': 'value'}})

# Хорошо: используй простые запросы (если возможно)
fetch('/api/users', {method: 'POST', headers: {'Content-Type': 'application/json'}})

3. Используй Access-Control-Max-Age

# Высокое значение = меньше preflight запросов
Access-Control-Max-Age: 86400  # 24 часа

# Низкое значение = чаще проверяется доступ
Access-Control-Max-Age: 300  # 5 минут

Заключение

OPTIONS — это критический метод для CORS. Понимание preflight запросов важно для:

  • Отладки проблем с CORS
  • Оптимизации производительности
  • Безопасности (CORS является механизмом безопасности браузера)
  • Проектирования API

В большинстве случаев фреймворки обрабатывают OPTIONS автоматически, но понимание механизма необходимо для опытного разработчика.