API da Web do MVC: nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado

128

Tentei tudo o que está escrito neste artigo: http://www.asp.net/web-api/overview/security/enabled-cross-origin-requests-in-web-api , mas nada funciona. Estou tentando obter dados do webAPI2 (MVC5) para usar em outro domínio usando angularJS.

meu controlador fica assim:

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
fonte
1
Também compartilhar seu código angular para solicitar coros
harishr
2
Provavelmente, não há problema com seu código angular pois a maioria dos problams CORS são apenas por causa da configuração do servidor
sam
Eu tenho o mesmo tipo de configuração, notei que quando solicito uma ação inexistente na API e o WebApi está retornando um 404, o cabeçalho CORS está ausente e o navegador reclama. Então, talvez seja tão simples assim.
Robin van der Knaap

Respostas:

296

Você precisa ativar o CORS em sua API da Web . A maneira mais fácil e preferida de ativar o CORS globalmente é adicionar o seguinte no 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>

Observe que os métodos são todos especificados individualmente, em vez de usar *. Isso ocorre porque ocorre um erro ao usar *.

Você também pode ativar o CORS por código.

Atualize
A seguir NuGet pacote é necessário: Microsoft.AspNet.WebApi.Cors.

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

        // ...
    }
}

Em seguida, você pode usar o [EnableCors]atributo em Actions ou Controllers como este

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

Ou você pode registrá-lo globalmente

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

        // ...
    }
}

Você também precisa lidar com as Options solicitações de comprovação com HTTP OPTIONSsolicitações.

Web APIprecisa responder à Optionssolicitação para confirmar se ela está realmente configurada para oferecer suporte CORS.

Para lidar com isso, tudo o que você precisa fazer é enviar uma resposta vazia de volta. Você pode fazer isso dentro de suas ações ou globalmente assim:

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

Essa verificação extra foi adicionada para garantir que as antigas APIsque foram projetadas para aceitar apenas GETe as POSTsolicitações não sejam exploradas. Imagine enviar uma DELETEsolicitação para um APIprojetado quando esse verbo não existia. O resultado é imprevisível e os resultados podem ser perigosos .

Mihai-Andrei Dinculescu
fonte
4
Sua resposta me ajudou. Eu tinha tentado tudo o que pude com as soluções de base de código. Não tentei a opção web.config até ler sua resposta. Foi o único que funcionou. Alguma idéia do porquê? Estou usando a API da Web 2 com OData. Obrigado mesmo assim! :)
Felipe Correa
1
Para referência futura, o pacote NuGet necessário é "Microsoft.AspNet.WebApi.Cors".
precisa saber é o seguinte
2
Eu segui todas as suas respostas e tenho duas perguntas: Onde deve ser invocado Application_BeginRequest ()? e segundo, no mesmo método, o .Contains ("Origin") não é realmente compilado para mim, de onde é esse método, String.Contains ou Linq.Contains?
meJustAndrew
2
lembre-se de que uma porta diferente # constitui um domínio diferente, que pode ser um problema. foo.com é um domínio diferente de foo.com:8080
RyBolt 11/16
2
Você salva minha vida;)
Paweł Groński
26

A resposta de @ Mihai-Andrei Dinculescu está correta, mas para o benefício dos pesquisadores, também há um ponto sutil que pode causar esse erro.

Adicionar um '/' no final do seu URL impedirá o EnableCors de funcionar em todas as instâncias (por exemplo, na página inicial).

Ou seja, isso não vai funcionar

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

mas isso vai funcionar:

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

O efeito é o mesmo se estiver usando o atributo EnableCors.

HockeyJ
fonte
Obrigado!! Foi útil.
Ankit Sahrawat 09/09/16
23

Eu segui todos os passos acima indicados por Mihai-Andrei Dinculescu .
Mas, no meu caso, eu precisava de mais uma etapa porque o http OPTIONS estava desativado no Web.Config pela linha abaixo.

<remove name="OPTIONSVerbHandler" />

Acabei de removê-lo do Web.Config (apenas comente como abaixo) e o Cors funciona como um encanto

<handlers>
  <!-- remove name="OPTIONSVerbHandler" / -->
</handlers>
AlbertSY
fonte
9

Pode ser por causa da instalação dos pacotes de nuget Cors.

Se você enfrentar o problema após instalar e habilitar os cors do nuget, poderá tentar reinstalar a API da web.

No gerenciador de pacotes, execute Update-Package Microsoft.AspNet.WebApi -reinstall

Bimal Das
fonte
Foi exatamente isso para mim. Eu instalei System.Web.Http.Cors e depois desinstalado, que deixou WebAPI na errado (recentemente atualizado) de versões entre 5.2.2 e 5.2.3
TaeKwonJoe
7

Tente isso, para garantir que você configurou o CORS corretamente:

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

Ainda não funciona? Verifique a presença de cabeçalhos HTTP.

Andrei
fonte
para verificar se o seu trabalho, o seu melhor para remover supportCredentials bem, ele faz desativar coros em certas condições
harishr
Melhor resposta, porque não quero habilitar o CORS para todo o site, apenas determinados pontos de extremidade. config.EnableCors()é necessário para isso também.
perfil completo de Csaba Toth
4

Para que qualquer protocolo CORS funcione, você precisa ter um método OPTIONS em cada nó de extremidade (ou um filtro global com esse método) que retornará esses cabeçalhos:

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

O motivo é que o navegador enviará primeiro uma solicitação OPTIONS para 'testar' seu servidor e ver as autorizações

sam
fonte
2

Eu pego o próximo caso sobre cors. Talvez seja útil para alguém. Se você adicionar o recurso 'Redirecionador WebDav' ao servidor, as solicitações PUT e DELETE falharão.

Portanto, você precisará remover o 'WebDAVModule' do seu servidor IIS:

  • "Na configuração dos módulos do IIS, faça um loop no WebDAVModule, se o seu servidor web tiver, e remova-o".

Ou adicione à sua configuração:

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

Andrey R
fonte
2

Eu sei que estou chegando tarde demais. No entanto, para quem está pesquisando, pensei em publicar o que FINALMENTE funcionou para mim. Não estou afirmando que é a melhor solução - apenas que funcionou.

Nosso serviço WebApi usa o método config.EnableCors (corsAttribute). No entanto, mesmo com isso, ainda falharia nos pedidos pré-voo. A resposta de Mihai-Andrei Dinculescu forneceu a pista para mim. Primeiro, adicionei o código Application_BeginRequest () para liberar as solicitações de opções. AINDA não funcionou para mim. O problema é que o WebAPI ainda não estava adicionando nenhum dos cabeçalhos esperados à solicitação OPTIONS. Liberar tudo sozinho não funcionou - mas me deu uma ideia. Adicionei os cabeçalhos personalizados que, de outra forma, seriam adicionados via web.config à resposta da solicitação OPTIONS. Aqui está o meu código:

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

Obviamente, isso se aplica apenas às solicitações OPTIONS. Todos os outros verbos são tratados pela configuração do CORS. Se houver uma abordagem melhor para isso, sou todo ouvidos. Parece uma trapaça para mim e eu preferiria que os cabeçalhos fossem adicionados automaticamente, mas foi o que finalmente funcionou e me permitiu seguir em frente.

John Groft
fonte
1

A resposta de Mihai-Andrei Dinculescu funcionou para mim, por exemplo:

  • Adicionando um <httpProtocol>no do web.config <system.webServer>secção
  • Retornando resposta vazia para OPTIONSsolicitações por meio do mencionado Application_BeginRequest()emglobal.asax

Exceto que o cheque dele Request.Headers.AllKeys.Contains("Origin")NÃO funcionou para mim, porque a solicitação continha um origing, assim com minúsculas. Acho que meu navegador (Chrome) envia assim para solicitações CORS.

Resolvi isso um pouco mais genericamente usando uma variante que não diferenciava maiúsculas de minúsculas do Containscheque: if (culture.CompareInfo.IndexOf(string.Join(",", Request.Headers.AllKeys), "Origin", CompareOptions.IgnoreCase) >= 0) {

Bart
fonte
0

Se você tiver nós security \ requestFiltering no seu web.config, da seguinte maneira:

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

certifique-se de adicionar isso também

<add verb="OPTIONS" allowed="true" />
ozz
fonte
0

Eu tinha tentado tudo o que pude encontrar na rede, incluindo os métodos que foram dados nesta resposta. Depois de quase tentar resolver o problema durante todo o dia, encontrei a solução que funcionou para mim como um encanto.

no arquivo WebApiConfig na pasta App_Start , comente todas as linhas de código e adicione o seguinte código:

`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
fonte
0

Eu sei que as pessoas provavelmente acharão isso muito óbvio no começo, mas realmente pensem nisso. Isso geralmente pode acontecer se você tiver feito algo errado.

Por exemplo, tive esse problema porque não adicionei uma entrada de host ao meu arquivo de hosts. O verdadeiro problema era a resolução do DNS. Ou entendi errado o URL base.

Às vezes, recebo esse erro se o token de identidade vier de um servidor, mas estou tentando usá-lo em outro.

Às vezes, você receberá esse erro se tiver errado o recurso.

Você pode conseguir isso se colocar o middleware CORS muito tarde na cadeia.

Bluebaron
fonte
0

Evite vários locais que habilitam o método CORS, como WebApiCOnfig.cs, GrantResourceOwnerCredentials no provedor e no atributo do cabeçalho do controlador, etc.

  1. Web tendo triplicado na interação com o banco de dados que você usou.
  2. Nuvem da AWS Se a VPC da Web API e do DB for diferente.

O código abaixo é mais do que suficiente para corrigir a origem de permissão de controle de acesso. // Verifique se app.UseCors deve estar no topo da linha de código da configuração.

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

Isso diminuiu o meu problema.

Sharad
fonte
0

Esse problema ocorre quando você tenta acessar de um domínio ou porta diferente.

Se você estiver usando o Visual Studio, vá para Ferramentas> Gerenciador de Pacotes NuGet> Console do Gerenciador de Pacotes. Lá você deve instalar o pacote NuGet Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

Em seguida, em PROJECT> App_Start> WebApiConfig, ative o 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:"*"));

        ....

    }
}

Depois de instalado com sucesso, construa a solução e isso deve ser suficiente

Tiago Martins Peres
fonte