Interfejs API sieci Web MVC: w żądanym zasobie nie ma nagłówka „Access-Control-Allow-Origin”

128

Wypróbowałem wszystko, co jest napisane w tym artykule: http://www.asp.net/web-api/overview/security/eniring-cross-origin-requests-in-web-api , ale nic nie działa. Próbuję uzyskać dane z webAPI2 (MVC5) do wykorzystania w innej domenie przy użyciu angularJS.

mój kontroler wygląda tak:

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;

        }      
    }
}
Noa Gani
źródło
1
Udostępnij
2
Prawdopodobnie nie ma problemu z jego kodem kątowym, ponieważ większość problemów związanych z CORS jest spowodowana tylko konfiguracją serwera
sam
Mam taką samą konfigurację, zauważyłem, że kiedy żądam nieistniejącej akcji w API, a WebApi zwraca 404, brakuje nagłówka CORS i przeglądarka będzie narzekać. Więc może to takie proste.
Robin van der Knaap

Odpowiedzi:

295

Musisz włączyć CORS w swoim Web Api . Łatwiejszym i preferowanym sposobem globalnego włączenia mechanizmu CORS jest dodanie następującego elementu do pliku 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>

Należy pamiętać, że metody są określane indywidualnie, zamiast używać *. Dzieje się tak, ponieważ podczas korzystania z *.

Możesz również włączyć CORS według kodu.

Aktualizować
Poniższy Nuget wymagany jest pakiet: Microsoft.AspNet.WebApi.Cors.

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

        // ...
    }
}

Następnie możesz użyć [EnableCors]atrybutu na akcjach lub kontrolerach, takich jak ten

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

Lub możesz zarejestrować go globalnie

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

        // ...
    }
}

Musisz również obsługiwać Options żądania inspekcji wstępnej z HTTP OPTIONSżądaniami.

Web APImusi odpowiedzieć na Optionsżądanie, aby potwierdzić, że rzeczywiście jest skonfigurowany do obsługi CORS.

Aby sobie z tym poradzić, wystarczy odesłać pustą odpowiedź . Możesz to zrobić w ramach swoich działań lub możesz to zrobić globalnie w następujący sposób:

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

To dodatkowe sprawdzenie zostało dodane, aby upewnić się, że stare, APIsktóre zostały zaprojektowane tylko do akceptowania GETi POSTżądań, nie zostaną wykorzystane. Wyobraź sobie, że wysyłasz DELETEżądanie do APIzaprojektowanego, gdy ten czasownik nie istnieje. Wynik jest nieprzewidywalny, a skutki mogą być niebezpieczne .

Mihai-Andrei Dinculescu
źródło
3
Twoja odpowiedź mi pomogła. Próbowałem wszystkiego, co mogłem, z rozwiązaniami bazowymi kodu. Nie wypróbowałem opcji web.config, dopóki nie przeczytałem Twojej odpowiedzi. To był jedyny, który działał. Masz jakiś pomysł, dlaczego? Używam Web API 2 z OData. W każdym razie dzięki! :)
Felipe Correa
1
Na przyszłość potrzebny do tego pakiet NuGet to „Microsoft.AspNet.WebApi.Cors”.
BrainSlugs83
2
Postępowałem zgodnie ze wszystkimi twoimi odpowiedziami i mam dwa pytania: Gdzie należy wywołać Application_BeginRequest ()? a po drugie, w tej samej metodzie .Contains („Origin”) tak naprawdę nie kompiluje się u mnie, skąd pochodzi ta metoda, String.Contains czy z Linq.Contains?
meJustAndrew
2
pamiętaj, że inny port # stanowi inną domenę, co może być problemem. foo.com to inna domena niż foo.com:8080
RyBolt
1
Ratujesz mi życie;)
Paweł Groński
26

Odpowiedź @ Mihai-Andrei Dinculescu jest poprawna, ale z korzyścią dla poszukujących jest również subtelny punkt, który może spowodować ten błąd.

Dodanie „/” na końcu adresu URL spowoduje, że EnableCors przestanie działać we wszystkich instancjach (np. Ze strony głównej).

To znaczy to nie zadziała

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

ale to zadziała:

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

Efekt jest taki sam, jeśli używasz atrybutu EnableCors.

HockeyJ
źródło
Dzięki!! To było pomocne.
Ankit Sahrawat
23

Wykonałem wszystkie powyższe kroki wskazane przez Mihai-Andrei Dinculescu .
Ale w moim przypadku potrzebowałem jeszcze 1 kroku, ponieważ http OPTIONS zostało wyłączone w Web.Config przez poniższy wiersz.

<remove name="OPTIONSVerbHandler" />

Właśnie usunąłem go z Web.Config (po prostu skomentuj jak poniżej) i Cors działa jak urok

<handlers>
  <!-- remove name="OPTIONSVerbHandler" / -->
</handlers>
AlbertSY
źródło
9

Może to być spowodowane instalacją pakietów nuget Cors.

Jeśli napotkasz problem po zainstalowaniu i włączeniu sterowników z nuget, możesz spróbować ponownie zainstalować interfejs API sieci Web.

Z menedżera pakietów uruchom Update-Package Microsoft.AspNet.WebApi -reinstall

Bimal Das
źródło
To było dokładnie to dla mnie. Zainstalowałem System.Web.Http.Cors, a następnie odinstalowałem, co pozostawiło WebApi na niewłaściwej (nowo zaktualizowanej) wersji między 5.2.2 a 5.2.3
TaeKwonJoe
7

Spróbuj tego, aby upewnić się, że poprawnie skonfigurowałeś CORS:

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

Wciąż nie działa? Sprawdź obecność nagłówków HTTP.

Andrei
źródło
aby sprawdzić, czy działa, lepiej usunąć również supportCredentials, wyłącza
cory
Najlepsza odpowiedź, ponieważ nie chcę włączać mechanizmu CORS dla całej mojej witryny, tylko dla niektórych punktów końcowych. config.EnableCors()jest do tego potrzebna.
Csaba Toth
4

Aby jakikolwiek protokół CORS działał, musisz mieć metodę OPTIONS na każdym punkcie końcowym (lub globalny filtr z tą metodą), która zwróci te nagłówki:

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

Powodem jest to, że przeglądarka najpierw wyśle ​​żądanie OPTIONS, aby „przetestować” serwer i zobaczyć uprawnienia

sam
źródło
2

Łapię następny przypadek o korsach. Może komuś się przyda. Jeśli dodasz funkcję „WebDav Redirector” do swojego serwera, żądania PUT i DELETE nie powiodą się.

Dlatego musisz usunąć „WebDAVModule” z serwera IIS:

  • „W konfiguracji modułów IIS, zapętl moduł WebDAVModule, jeśli Twój serwer sieciowy go ma, a następnie usuń”.

Lub dodaj do swojej konfiguracji:

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

Andrey R.
źródło
2

Wiem, że przyjdę do tego bardzo późno. Jednak dla każdego, kto szuka, pomyślałem, że opublikuję to, co W KOŃCU dla mnie zadziałało. Nie twierdzę, że to najlepsze rozwiązanie - tylko że zadziałało.

Nasza usługa WebApi korzysta z metody config.EnableCors (corsAttribute). Jednak nawet z tym nadal nie powiedzie się w przypadku żądań przed lotem. Odpowiedź @ Mihai-Andrei Dinculescu dała mi wskazówkę. Przede wszystkim dodałem jego kod Application_BeginRequest (), aby opróżnić żądania opcji. To NADAL nie działało dla mnie. Problem polega na tym, że WebAPI nadal nie dodaje żadnego z oczekiwanych nagłówków do żądania OPTIONS. Samo spłukiwanie nie zadziałało - ale dało mi pewien pomysł. Dodałem niestandardowe nagłówki, które w przeciwnym razie zostałyby dodane za pośrednictwem pliku web.config do odpowiedzi na żądanie OPTIONS. Oto mój kod:

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();
  }
}

Oczywiście dotyczy to tylko żądań OPCJI. Wszystkie inne zlecenia są obsługiwane przez konfigurację CORS. Jeśli istnieje lepsze podejście do tego, mam wszystkie uszy. Wydaje mi się, że to oszustwo i wolałbym, aby nagłówki były dodawane automatycznie, ale to w końcu zadziałało i pozwoliło mi przejść dalej.

John Groft
źródło
1

Odpowiedź @ Mihai-Andrei Dinculescu zadziałała dla mnie, np .:

  • Dodanie <httpProtocol>w pliku web.config w <system.webServer>sekcji
  • Zwracanie pustej odpowiedzi na OPTIONSzapytania za pośrednictwem wspomnianego Application_BeginRequest()wglobal.asax

Tyle że jego czek na Request.Headers.AllKeys.Contains("Origin")mnie NIE zadziałał, ponieważ żądanie zawierało origing, więc z małymi literami. Myślę, że moja przeglądarka (Chrome) wysyła to w ten sposób dla żądań CORS.

Rozwiązałem to nieco bardziej ogólnie, używając zamiast tego wariantu jego czeku niewrażliwego na wielkość literContains : if (culture.CompareInfo.IndexOf(string.Join(",", Request.Headers.AllKeys), "Origin", CompareOptions.IgnoreCase) >= 0) {

Bart
źródło
0

Jeśli masz węzły security \ requestFiltering w pliku web.config w następujący sposób:

<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>

upewnij się, że również to dodałeś

<add verb="OPTIONS" allowed="true" />
ozz
źródło
0

Wypróbowałem wszystko, co mogłem znaleźć w sieci, w tym metody podane w tej odpowiedzi. Po prawie całodziennej próbie rozwiązania problemu znalazłem rozwiązanie, które zadziałało na mnie jak urok.

w pliku WebApiConfig w folderze App_Start skomentuj wszystkie wiersze kodu i dodaj następujący kod:

`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");
        }
    }`
Yagnesh Khamar
źródło
0

Wiem, że ludzie prawdopodobnie uznają to za bardzo oczywiste na początku, ale naprawdę pomyśl o tym. Może się to często zdarzyć, jeśli zrobiłeś coś złego.

Na przykład miałem ten problem, ponieważ nie dodałem wpisu hosta do mojego pliku hosts. Prawdziwym problemem było rozpoznawanie nazw DNS. Lub po prostu otrzymałem nieprawidłowy podstawowy adres URL.

Czasami pojawia się ten błąd, jeśli token tożsamości pochodzi z jednego serwera, ale próbuję go użyć na innym.

Czasami pojawia się ten błąd, jeśli masz zły zasób.

Możesz to uzyskać, jeśli umieścisz oprogramowanie pośredniczące CORS zbyt późno w łańcuchu.

Bluebaron
źródło
0

Unikaj włączania wielu miejsc CORS, takich jak WebApiCOnfig.cs, metoda GrantResourceOwnerCredentials w atrybucie dostawcy i nagłówka kontrolera itp. Poniżej znajduje się lista, która również powoduje kontrolę dostępu Zezwalaj na pochodzenie

  1. Sieć ma możliwości interakcji z bazą danych, z której korzystałeś.
  2. AWS Cloud Jeśli VPC Web API i DB są różne.

Poniższy kod jest więcej niż wystarczający, aby naprawić kontrolę dostępu zezwalającą na pochodzenie. // Upewnij się, że app.UseCors powinien znajdować się na górze linii kodu konfiguracji.

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

To spowolniło mój problem.

Sharad
źródło
0

Ten problem występuje, gdy próbujesz uzyskać dostęp z innej domeny lub innego portu.

Jeśli używasz programu Visual Studio, przejdź do pozycji Narzędzia> Menedżer pakietów NuGet> Konsola Menedżera pakietów. Tam musisz zainstalować pakiet NuGet Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

Następnie w PROJECT> App_Start> WebApiConfig włącz 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:"*"));

        ....

    }
}

Po pomyślnym zainstalowaniu skompiluj rozwiązanie i to powinno wystarczyć

Tiago Martins Peres 李大仁
źródło