CORS (Cross-Origin Resource Sharing)
Волга поддерживает легко настраиваемый middleware для CORS.
Он входит в состав набора функций full. Однако, если вы его не используете, вы можете включить функцию middleware в Cargo.toml, чтобы добавить поддержку CORS:
[dependencies]
volga = { version = "...", features = ["middleware"] }
Базовая настройка
Следующий пример демонстрирует максимально разрешительную конфигурацию CORS:
use volga::App;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new()
.with_cors(|cors| cors
.with_any_origin()
.with_any_header()
.with_any_method());
// Включение CORS middleware
app.use_cors();
app.map_post("/", || async {});
app.run().await
}
По умолчанию CORS отключен. Чтобы избежать паники во время выполнения, необходимо вызвать метод with_cors() до use_cors().
Если требуется более строгая конфигурация, можно указать конкретные разрешённые источники, заголовки и методы:
use volga::{App, http::Method};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new()
.with_cors(|cors| cors
.with_origins(["http://example.com", "http://example.net"])
.with_headers(["Cache-Control", "Content-Language"])
.with_methods([Method::GET, Method::POST]));
// Включение CORS middleware
app.use_cors();
app.map_post("/", || async {});
app.run().await
}
Примечание
Если вам нужно включить передачу учётных данных с помощью with_credentials(), учтите, что нельзя использовать эту настройку совместно с wildcard-значениями для источников, заголовков или методов по соображениям безопасности. Эти ограничения проверяются в use_cors(), и в случае некорректной конфигурации произойдёт паника. Метод не принимает аргументов — для явного отключения используйте without_credentials(). Аналогично, заголовок Vary управляется через with_vary_header() / without_vary_header().
Политики CORS и область действия
Волга разделяет конфигурацию CORS и место её применения:
with_cors()определяет одну или несколько политик CORS.use_cors()включает CORS middleware (обязательно).- CORS применяется на основе:
- Политики по умолчанию (применяется ко всем маршрутам, если не переопределена) или
- Именованной политики (применяется только там, где это явно указано).
Именованная политика для группы маршрутов
Если вы настроите только именованную политику, маршруты не получат CORS, если вы явно не прикрепите эту политику с помощью cors_with(...).
use volga::App;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new()
.with_cors(|cors| cors
.with_name("policy")
.with_origins(["https://example.com"])
.with_any_header()
.with_any_method());
// Включить middleware (обязательно)
app.use_cors();
app.group("/api", |api| {
// Применить CORS только для `/api/*`
api.cors_with("policy");
api.map_get("/users", || async {});
api.map_post("/posts", || async {});
});
// Здесь CORS не применяется (именнованная политика не применяется)
app.map_get("/internal", || async {});
app.run().await
}
Именованная политика для отдельного маршрута
Вы можете прикрепить политику к одному маршруту:
use volga::App;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new()
.with_cors(|cors| cors
.with_name("permissive")
.with_any_origin()
.with_any_method()
.with_any_header());
app.use_cors();
app.map_get("/public", || async {})
.cors_with("permissive");
app.map_get("/private", || async {})
.disable_cors();
app.run().await
}
Примечание
При использовании только именованных политик маршруты без явно прикрепленной политики не будут отправлять заголовки CORS.
Переопределение и отключение
CORS можно явно отключить для маршрута (или группы) с помощью disable_cors(). Это особенно полезно, когда у вас есть политика по умолчанию, включенная глобально, но вам нужно отключить ее для определенных конечных точек.
CORS для несовпавших запросов
Ответы 404 и 405 несут те же заголовки CORS, которые настроенная политика проставила бы на 200: глобальный middleware выполняется и для запросов, не совпавших ни с одним маршрутом, поэтому браузер получает осмысленную ошибку CORS вместо непрозрачной.
На preflight по-прежнему отвечают 204 только для существующего маршрута — ответить так на путь или метод, которые роутер не нашёл, значило бы объявить эндпоинт, которого нет. Такие запросы проваливаются в 404 / 405 и забирают заголовки на выходе. Middleware CORS различает эти случаи через matched_route().
Статические файлы
Политика CORS группы маршрутов до раздаваемых этой группой файлов не доходит. Политика выбирается по сработавшему маршруту, а статический файл раздаётся без маршрута, поэтому к файлам применяется политика приложения — заданная через with_cors(). По той же причине preflight, нацеленный на путь файла, обрабатывается как запрос к несуществующему пути: 404 с заголовками политики, а не 204. Кросс-доменные GET к статике его всё равно никогда не отправляют.
Полный пример доступен здесь.