ActixMiddleTechnical
Как настроить CORS в Actix-web?
Подключите крейт actix-cors и зарегистрируйте Cors::default() через App::wrap() первым в цепочке; настройте allowed_origin, allowed_methods, allowed_headers и supports_credentials() под нужды вашего SPA.
Настройка CORS в Actix-web
Для настройки CORS используется крейт actix-cors, который предоставляет готовый middleware Cors. Он реализует трейт Transform и регистрируется через App::wrap().
Добавьте зависимость в Cargo.toml:
[dependencies]
actix-web = "4"
actix-cors = "0.7"
Пример конфигурации для типичного SPA-приложения:
use actix_cors::Cors;
use actix_web::{http, middleware::Logger, web, App, HttpServer, HttpResponse};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
// Настройка CORS для конкретного origin
let cors = Cors::default()
.allowed_origin("https://app.example.com")
.allowed_origin("http://localhost:3000")
.allowed_methods(vec!["GET", "POST", "PUT", "DELETE", "PATCH"])
.allowed_headers(vec![
http::header::AUTHORIZATION,
http::header::CONTENT_TYPE,
http::header::ACCEPT,
])
.expose_headers(vec![http::header::CONTENT_DISPOSITION])
.supports_credentials() // разрешает cookie/credentials
.max_age(3600); // кэш preflight на 1 час
App::new()
.wrap(cors)
.wrap(Logger::default())
.route("/api/data", web::get().to(data_handler))
})
.bind("0.0.0.0:8080")?
.run()
.await
}
async fn data_handler() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({ "ok": true }))
}
Для полностью открытого API (публичный сервис без credentials) можно использовать:
let cors = Cors::permissive(); // эквивалент Access-Control-Allow-Origin: *
Для динамической проверки origin используйте метод allowed_origin_fn:
let cors = Cors::default()
.allowed_origin_fn(|origin, _req_head| {
origin.as_bytes().ends_with(b".example.com")
})
.allowed_methods(vec!["GET", "POST"]);
Порядок wrap важен: CORS должен быть первым (ближайшим к сети), чтобы preflight OPTIONS-запросы обрабатывались до любой аутентификации.
Подводные камни
supports_credentials()несовместим сallowed_origin("*")илиCors::permissive()— браузер отклонит такой ответ; нужно явно указать конкретный origin.- Порядок wrap: если middleware аутентификации зарегистрирован раньше CORS, preflight OPTIONS-запросы будут отклонены с 401 до того, как CORS-заголовки будут добавлены.
- Отсутствие заголовка
CONTENT_TYPEвallowed_headers: POST с JSON-телом отправляет preflight, и без разрешённогоContent-Typeон провалится. - Кэш preflight (
max_age): слишком большое значение затрудняет отладку при изменении политики; в разработке лучше ставить 0 или 1. - Не добавлять кастомные заголовки в
expose_headers: если сервер отдаёт, например,X-Request-Id, браузер скроет его от JS, если заголовок не объявлен в expose. Cors::default()без явногоallowed_originблокирует все запросы с другого origin — это не «разрешить всё», а «запретить всё».- HTTPS/HTTP несоответствие: origin
http://localhost:3000иhttps://localhost:3000— разные origins; оба нужно перечислить явно.
Common mistakes
- Отвечать определением без production-сценария.
- Не называть runtime boundary, security boundary или failure mode.
- Игнорировать версию API, observability и тестовую проверку.
What the interviewer is testing
- Объясняет механизм своими словами и без выдуманных API.
- Называет реальные риски, диагностику и критерий корректности.
- Связывает ответ с текущей документацией и миграционными ограничениями.