MVC web api: заголовок "Access-Control-Allow-Origin" отсутствует на запрошенном ресурсе

Я пробовал все, что написано в этой статье: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api, но ничего не работает. Я пытаюсь получить данные из webAPI2 (MVC5) для использования в другом домене с помощью angularJS.

мой контроллер выглядит следующим образом:

namespace tapuzWebAPI.Controllers
{
    [EnableCors(origins: "http://local.tapuz.co.il", headers: "*", methods: "*", SupportsCredentials = true)]
    [RoutePrefix("api/homepage")]
    public class HomePageController : ApiController
    {
        [HttpGet]
        [Route("GetMainItems")]
        //[ResponseType(typeof(Product))]
        public List<usp_MobileSelectTopSecondaryItemsByCategoryResult> GetMainItems()
        {


            HomePageDALcs dal = new HomePageDALcs();
            //Three product added to display the data

            //HomePagePromotedItems.Value.Add(new HomePagePromotedItem.Value.FirstOrDefault((p) => p.ID == id));


            List<usp_MobileSelectTopSecondaryItemsByCategoryResult> items = dal.MobileSelectTopSecondaryItemsByCategory(3, 5);
            return items;

        }      
    }
}

Ответ 1

Вам нужно включить CORS в Web Api. Более простой и предпочтительный способ включения CORS во всем мире состоит в том, чтобы добавить следующее в web.config

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Обратите внимание, что все методы задаются индивидуально, вместо использования *. Это связано с тем, что при использовании * появляется ошибка.

Вы также можете включить CORS по коду.

Обновление
Требуется следующий пакет NuGet: Microsoft.AspNet.WebApi.Cors.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.EnableCors();

        // ...
    }
}

Затем вы можете использовать атрибут [EnableCors] в действиях или контроллерах, таких как

[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")]

Или вы можете зарегистрировать его по всему миру

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("http://www.example.com", "*", "*");
        config.EnableCors(cors);

        // ...
    }
}

Вам также необходимо обработать запросы предпросмотра Options с запросами HTTP OPTIONS.

Web API должен ответить на запрос Options, чтобы подтвердить, что он действительно настроен на поддержку CORS.

Чтобы справиться с этим, все, что вам нужно сделать, это отправить пустой ответ. Вы можете сделать это внутри своих действий, или вы можете сделать это глобально следующим образом:

# Global.asax.cs
protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
        Response.Flush();
    }
}

Эта дополнительная проверка была добавлена, чтобы гарантировать, что старые APIs, которые были предназначены для принятия только запросов GET и POST, не будут использоваться. Представьте, что вы отправили запрос DELETE в API, когда этот глагол не существовал. Результат непредсказуем, и результаты могут быть опасными.

Ответ 2

@Ответ Михая-Андрея Динкулеску правильный, но в интересах поисковиков есть также тонкая точка, которая может вызвать эту ошибку.

Добавление '/' в конец вашего URL-адреса прекратит работу EnableCors во всех экземплярах (например, с домашней страницы).

т.е. Это не сработает

var cors = new EnableCorsAttribute("http://testing.azurewebsites.net/", "*", "*");
config.EnableCors(cors);

но это будет работать:

var cors = new EnableCorsAttribute("http://testing.azurewebsites.net", "*", "*");
config.EnableCors(cors);

Эффект тот же, если используется атрибут EnableCors.

Ответ 3

Я следил за всеми шагами, указанными Михаем-Андреем Динкулеску.
Но в моем случае мне понадобился шаг еще 1, потому что http OPTIONS был отключен в Web.Config по строке ниже.

<remove name="OPTIONSVerbHandler" />

Я просто удалил его из Web.Config(просто прокомментируйте его, как показано ниже), и Cors работает как шарм

<handlers>
  <!-- remove name="OPTIONSVerbHandler" / -->
</handlers>

Ответ 4

Возможно, это связано с установкой пакетов Cors nuget.

Если вы столкнулись с проблемой после установки и установки кода из nuget, вы можете попробовать переустановить веб-Api.

В диспетчере пакетов запустите Update-Package Microsoft.AspNet.WebApi -reinstall

Ответ 5

Попробуйте это, чтобы убедиться, что вы правильно настроили CORS:

[EnableCors(origins: "*", headers: "*", methods: "*")]

Все еще не работает? Проверьте наличие заголовков HTTP.

Ответ 6

Чтобы протокол CORS работал, вам необходимо иметь метод OPTIONS на каждой конечной точке (или глобальный фильтр с помощью этого метода), который будет возвращать эти заголовки:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: content-type

Причина в том, что браузер сначала отправит запрос OPTIONS для "проверки" вашего сервера и просмотра разрешений

Ответ 7

@Ответ Михай-Андрея Динкулеску работал у меня, например:

  • Добавление <httpProtocol> в раздел web.config <system.webServer>
  • Возвращая пустой ответ для запросов OPTIONS через упомянутый Application_BeginRequest() в global.asax

За исключением того, что его проверка на Request.Headers.AllKeys.Contains("Origin") НЕ работала для меня, потому что запрос содержал origing, поэтому с нижним регистром. Я думаю, что мой браузер (Chrome) отправляет его таким образом для запросов CORS.

Я решил это более универсально, используя нечувствительный к регистру вариант своей проверки Contains вместо этого: if (culture.CompareInfo.IndexOf(string.Join(",", Request.Headers.AllKeys), "Origin", CompareOptions.IgnoreCase) >= 0) {

Ответ 8

Please make this change in webapi.config file to enable cors and avoid the below error

asp.net webapi Ответ на запрос предварительной проверки не проходит проверку контроля доступа: в запрашиваемом ресурсе отсутствует заголовок "Access-Control-Allow-Origin".

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        var cors = new EnableCorsAttribute("*", "*", "*");

        config.EnableCors(cors);

       //... existing values in register seection
     }

}

Ответ 9

Я поймал следующий случай о корсах. Может быть, это кому-нибудь пригодится. Если вы добавляете функцию "WebDav Redirector" на свой сервер, запросы PUT и DELETE не выполняются.

Итак, вам нужно удалить "WebDAVModule" с вашего сервера IIS:

  • "В конфигурации модулей IIS зафиксируйте модуль WebDAVModule, если он есть на вашем веб-сервере, а затем удалите его".

Или добавьте в свой конфиг:

<system.webServer>
<modules>
  <remove name="WebDAVModule"/>
</modules>
<handlers>
  <remove name="WebDAV" />
  ...
</handlers>

Ответ 10

Если в вашем файле web.config есть узлы security\requestFiltering, выполните следующие действия:

<security>
  <requestFiltering>
    <verbs allowUnlisted="false">
      <add verb="GET" allowed="true" />
      <add verb="POST" allowed="true" />
      <add verb="PUT" allowed="true" />
      <add verb="DELETE" allowed="true" />
      <add verb="DEBUG" allowed="true" />          
    </verbs>
  </requestFiltering>

убедитесь, что вы добавили это также

<add verb="OPTIONS" allowed="true" />

Ответ 11

Я перепробовал все, что мог найти в сети, включая методы, которые были даны в этом ответе. После почти полной попытки решить проблему в течение целого дня я нашел решение, которое сработало для меня, как шарм.

в файле WebApiConfig в папке App_Start закомментируйте все строки кода и добавьте следующий код:

'public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.EnableCors();
        var enableCorsAttribute = new EnableCorsAttribute("*",
                                           "Origin, Content-Type, Accept",
                                           "GET, PUT, POST, DELETE, OPTIONS");
        config.EnableCors(enableCorsAttribute);
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            //routeTemplate: "api/{controller}/{id}",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        config.Formatters.Add(new BrowserJsonFormatter());
    }

    public class BrowserJsonFormatter : JsonMediaTypeFormatter
    {
        public BrowserJsonFormatter()
        {
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            this.SerializerSettings.Formatting = Formatting.Indented;
        }

        public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        {
            base.SetDefaultContentHeaders(type, headers, mediaType);
            headers.ContentType = new MediaTypeHeaderValue("application/json");
        }
    }'

Ответ 12

Я знаю, что приду к этому очень поздно. Тем не менее, для всех, кто искал, я думал, что опубликую то, что НАКОНЕЦ работает для меня. Я не претендую на это лучшее решение - только то, что это сработало.

Наш сервис WebApi использует метод config.EnableCors(corsAttribute). Однако, даже с этим, это все еще отказало бы на запросах перед полетом. @Михай-Андрей Динкулеску ответ дал мне подсказку. Прежде всего, я добавил его код Application_BeginRequest() для очистки запросов опций. Это все еще не работает для меня. Проблема в том, что WebAPI все еще не добавляет ожидаемые заголовки в запрос OPTIONS. Промывка в одиночку не сработала - но это дало мне идею. Я добавил пользовательские заголовки, которые в противном случае были бы добавлены через web.config в ответ на запрос OPTIONS. Вот мой код:

protected void Application_BeginRequest()
{
  if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
  {
    Response.Headers.Add("Access-Control-Allow-Origin", "https://localhost:44343");
    Response.Headers.Add("Access-Control-Allow-Headers",
      "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
    Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    Response.Flush();
  }
}

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