Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Для работы с CORS в прошлой теме применялся следующий класс Startup:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace CorsApp { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddCors(); // добавляем сервисы CORS } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseRouting(); // подключаем CORS app.UseCors(builder => builder.AllowAnyOrigin()); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); }); } } }
В вызове app.UseCors с помощью методов объекта CorsPolicyBuilder можно настроить конфигурацию CORS:
AllowAnyOrigin(): принимаются запросы с любого адреса
AllowAnyHeader(): принимаются запросы с любыми заголовками
AllowAnyMethod(): принимаются запросы любого типа (GET/POST)
AllowCredentials(): разрешается принимать идентификационные данные от клиента (например, куки)
WithHeaders(): принимаются только те запросы, которые используют содержат определенные заголовки
WithMethods(): принимаются запросы только определенного типа
WithOrigins(): принимаются запросы только с определенных адресов
WithExposedHeaders(): позволяет серверу отправлять на сторону клиента свои заголовки
Метод AllowAnyOrigin() позволяет установить взаимодействие с любым приложением по любому адресу. Однако подобное поведение может быть нежелательным. В этом случае мы можем ограничить круг адресов с помощью метода WithOrigins():
app.UseCors(builder => builder.WithOrigins("http://example.com", "http://google.com"));
При чем, что важно, в конце названия домена не должно быть конечного слеша.
Метод AllowAnyMethod() позволяет принимать запросы любого типа (GET/POST). Также можно настроить принятие только определенного типа запросов:
app.UseCors(builder => builder.WithOrigins("https://localhost:44321").WithMethods("GET"));
Для разрешения запросов с любыми заголовками применяется метод AllowAnyHeader(). Следует отметить, что вместе с этим методом лучше также указывать и метод AllowAnyMethod() или WithMethods() для указания типа запроса:
app.UseCors(builder => builder.WithOrigins("https://localhost:44321") .AllowAnyHeader() .AllowAnyMethod());
Если необходимо принимать запросы только с определенными заголовоками, то все требуемые заголовки надо передать в метод WithHeaders():
app.UseCors(builder => builder.WithOrigins("https://localhost:44321") .AllowAnyMethod() .WithHeaders("accept", "content-type", "origin", "custom-header"));
Если в метод передаются заголовки, отличные от "*", то следует указать по крайней мере три заголовка "accept", "content-type", "origin", а также какие-то свои заголовки, например, как в данном случае "custom-header".
Если сервер отправляет какие-то свои заголовки, то по умолчанию клиент их не получает. Чтобы на стороне сервера указать, какие заголовки может получать клиент, следует использовать метод WithExposedHeaders():
public void Configure(IApplicationBuilder app) { app.UseCors(builder => builder.WithOrigins("https://localhost:44321") .AllowAnyMethod() .AllowAnyHeader() .WithExposedHeaders("custom-header")); app.Run(async (context) => { context.Response.Headers.Add("custom-header", "5678"); await context.Response.WriteAsync("Hello World!"); }); }
Сервер устанавливает заголовок custom-header и отправляет его клиенту. Чтобы клиент получил этот заголовок, он передается в метод WithExposedHeaders.
Затем на стороне клиента можно получить значение этого заголовка:
var btn = document.getElementById("btn"); var result = document.getElementById("result"); var headers = document.getElementById("headers"); var request = new XMLHttpRequest(); btn.addEventListener("click", function (e) { request.open("GET", "https://localhost:44313/"); request.onreadystatechange = reqReadyStateChange; request.send(); }); function reqReadyStateChange() { if (request.readyState == 4) { if (request.status == 200){ result.innerText = request.responseText; // получаем заголовок headers.innerText = request.getResponseHeader("custom-header"); } } }
По умолчанию браузер не посылает никаких идентификационных данных. Подобные данные включают куки, а также данные HTTP-аутентификации. Для отправки идентификационных данных в кроссдоменном запросе на стороне клиента у объекта XMLHttpRequest необходимо установить свойство withCredentials равным true.
var request = new XMLHttpRequest(); request.open("GET", "https://localhost:44313/"); request.withCredentials = true;
Для получения данных на стороне сервера применяется метод AllowCredentials(). Этот метод устанавливает заголовок Access-Control-Allow-Credentials
,
который говорит браузеру, что сервер разрешает отправку идентификационных данных. При этом данный метод не может использоваться с методом AllowAllOrigin, то
есть обязательно нужно указать набор адресов, с которыми будет взаимодействовать сервер. Например:
public void Configure(IApplicationBuilder app) { app.UseCors(builder => builder.WithOrigins("https://localhost:44321") .AllowCredentials()); app.Run(async (context) => { var login = context.Request.Cookies["login"]; // получаем отправленные куки await context.Response.WriteAsync($"Hello {login}!"); }); }
На стороне клиента отправка куки могла бы выглядеть следующим образом:
var btn = document.getElementById("btn"); var request = new XMLHttpRequest(); document.cookie = "login=tom32;"; // куки, которые будут отправляться btn.addEventListener("click", function (e) { request.open("GET", "https://localhost:44313/"); request.onreadystatechange = reqReadyStateChange; request.withCredentials = true; request.send(); }); function reqReadyStateChange() { if (request.readyState == 4) { if (request.status == 200) console.log(request.responseText); } }