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

128

Я перепробовал все, что написано в этой статье: http://www.asp.net/web-api/overview/security/enpting-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
Также поделитесь своим кодом angular для запроса
cors
2
Вероятно, нет проблем с его кодом angular, поскольку большинство проблем CORS возникают только из-за конфигурации сервера
Сэм
У меня такая же настройка, я заметил, что когда я запрашиваю несуществующее действие в API, а WebApi возвращает 404, заголовок CORS отсутствует, и браузер будет жаловаться. Так что, может быть, это так просто.
Робин ван дер Кнаап

Ответы:

296

Вам необходимо включить CORS в вашем веб-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разработанному объекту, когда этого глагола не существует. Результат непредсказуем, а результаты могут быть опасными .

Михай-Андрей Динкулеску
источник
4
Ваш ответ мне помог. Я пробовал все, что мог, с решениями для кодовой базы. Я не пробовал использовать параметр web.config, пока не прочитал ваш ответ. Это было единственное, что сработало. Есть идеи, почему? Я использую Web API 2 с OData. Спасибо, в любом случае! :)
Фелипе Корреа
1
Для справки в будущем вам понадобится пакет NuGet «Microsoft.AspNet.WebApi.Cors».
BrainSlugs83
2
Я следил за всем вашим ответом, и у меня есть два вопроса: где следует вызывать Application_BeginRequest ()? и, во-вторых, в том же методе .Contains ("Origin") на самом деле не компилируется у меня, откуда этот метод, String.Contains или Linq.Contains?
meJustAndrew
2
помните, что другой порт # представляет собой другой домен, что может быть ошибкой. foo.com - это другой домен, чем foo.com:8080
RyBolt
2
Вы
спасаете
26

Ответ @ Mihai-Andrei Dinculescu верен, но в интересах поисковиков есть также тонкий момент, который может вызвать эту ошибку.

Добавление символа '/' в конце вашего 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.

HockeyJ
источник
Спасибо!! Это было полезно.
Анкит Сахрават
23

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

<remove name="OPTIONSVerbHandler" />

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

<handlers>
  <!-- remove name="OPTIONSVerbHandler" / -->
</handlers>
AlbertSY
источник
9

Это может быть из-за установки пакетов Cors nuget.

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

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

Бимал Дас
источник
Это было как раз для меня. Я установил System.Web.Http.Cors, а затем удалил, что оставило WebApi на неправильной (недавно обновленной) версии между 5.2.2 и 5.2.3
TaeKwonJoe
7

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

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

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

Андрей
источник
чтобы проверить, работает ли он, лучше также удалить supportCredentials, он отключает cors в определенных условиях
harishr
Лучший ответ, потому что я не хочу включать CORS для всего моего сайта, только для определенных конечных точек. config.EnableCors()для этого тоже нужно.
Csaba Toth
4

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

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

Причина в том, что браузер сначала отправит запрос OPTIONS, чтобы "протестировать" ваш сервер и увидеть авторизации.

Сэм
источник
2

Ловлю очередной случай про корс. Может кому будет полезно. Если вы добавите на свой сервер функцию «Перенаправитель WebDav», запросы PUT и DELETE не будут выполнены.

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

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

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

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

Андрей Р
источник
2

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

Наша служба 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. Если есть лучший подход к этому, я весь уши. Мне кажется, что это чит, и я бы предпочел, чтобы заголовки добавлялись автоматически, но это то, что наконец сработало и позволило мне двигаться дальше.

Джон Грофт
источник
1

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

  • Добавление <httpProtocol>в <system.webServer>раздел web.config
  • Возвращение пустого ответа на 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) {

Барт
источник
0

Если у вас есть узлы security \ requestFiltering в вашем web.config следующим образом:

<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" />
Ozz
источник
0

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

в файле 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");
        }
    }`
Ягнеш Хамар
источник
0

Я знаю, что люди, вероятно, сначала сочтут это очевидным, но на самом деле подумайте об этом. Это часто может случиться, если вы сделали что-то не так.

Например, у меня была эта проблема, потому что я не добавил запись хоста в свой файл hosts. Настоящая проблема заключалась в разрешении DNS. Или я просто неправильно указал базовый URL.

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

Иногда вы получаете эту ошибку, если неправильно указали ресурс.

Вы можете получить это, если слишком поздно поместите промежуточное ПО CORS в цепочку.

Bluebaron
источник
0

Избегайте включения CORS в нескольких местах, например, WebApiCOnfig.cs, метода GrantResourceOwnerCredentials в поставщике и атрибуте заголовка контроллера и т. Д. Ниже приведен список, который также вызывает разрешение контроля доступа.

  1. Веб не может взаимодействовать с БД, которую вы использовали.
  2. AWS Cloud Если VPC веб-API и БД отличаются.

Приведенного ниже кода более чем достаточно, чтобы исправить источник разрешения управления доступом. // Убедитесь, что app.UseCors должен быть в верхней части строки кода конфигурации.

   public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            //All other configurations
        }
    }

Это замедлило мою проблему.

Шарада
источник
0

Эта проблема возникает, когда вы пытаетесь получить доступ из другого домена или другого порта.

Если вы используете Visual Studio, перейдите в Инструменты> Диспетчер пакетов NuGet> Консоль диспетчера пакетов. Там вам нужно установить пакет NuGet Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

Затем в PROJECT> App_Start> WebApiConfig включите CORS

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        
        //Enable CORS. Note that the domain doesn't have / in the end.
        config.EnableCors(new EnableCorsAttribute("https://tiagoperes.eu",headers:"*",methods:"*"));

        ....

    }
}

После успешной установки создайте решение, и этого должно быть достаточно

Тьяго Мартинс Перес 李大仁
источник