MVC web api: No hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado

128

Intenté todo lo que está escrito en este artículo: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api , pero nada funciona. Estoy tratando de obtener datos de webAPI2 (MVC5) para usar en otro dominio usando angularJS.

mi controlador se ve así:

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
fuente
1
También comparta su código angular para solicitar cors
harishr
2
Probablemente no hay ningún problema con su código angular ya que la mayoría de los problams CORS son sólo debido a la configuración del servidor
sam
Tengo el mismo tipo de configuración, noté que cuando solicito una acción no existente en la API, y WebApi está devolviendo un 404, falta el encabezado CORS y el navegador se quejará. Entonces, tal vez sea tan simple como eso.
Robin van der Knaap

Respuestas:

296

Debe habilitar CORS en su API web . La forma más fácil y preferida de habilitar CORS a nivel mundial es agregar lo siguiente en 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>

Tenga en cuenta que los métodos se especifican individualmente, en lugar de usarlos *. Esto se debe a que se produce un error al usarlo *.

También puede habilitar CORS por código.

Modificar
la siguiente NuGet se requiere paquete: Microsoft.AspNet.WebApi.Cors.

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

        // ...
    }
}

Luego puede usar el [EnableCors]atributo en acciones o controladores como este

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

O puedes registrarlo globalmente

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

        // ...
    }
}

También debe manejar las Options solicitudes de verificación previa con HTTP OPTIONSsolicitudes.

Web APInecesita responder a la Optionssolicitud para confirmar que está configurada para admitir CORS.

Para manejar esto, todo lo que necesita hacer es enviar una respuesta vacía . Puedes hacer esto dentro de tus acciones, o puedes hacerlo globalmente así:

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

Esta verificación adicional se agregó para garantizar que los antiguos APIsque fueron diseñados para aceptar solo GETy las POSTsolicitudes no sean explotadas. Imagina enviar una DELETEsolicitud a un APIdiseñado cuando este verbo no existe. El resultado es impredecible y los resultados pueden ser peligrosos .

Mihai-Andrei Dinculescu
fuente
44
Tu respuesta me ayudó. Había intentado todo lo que pude con las soluciones de código base. No probé la opción web.config hasta que leí tu respuesta. Fue el único que funcionó. ¿Alguna idea de por qué? Estoy usando Web API 2 con OData. ¡Gracias de cualquier manera! :)
Felipe Correa
1
Para referencia futura, el paquete NuGet que necesita para esto es "Microsoft.AspNet.WebApi.Cors".
BrainSlugs83
2
He seguido toda su respuesta y tengo dos preguntas: ¿Dónde se debe invocar Application_BeginRequest ()? y segundo, en el mismo método, .Contains ("Origin") realmente no se compila conmigo, ¿de dónde es este método, String.Contains o Linq.Contains?
meJustAndrew
2
recuerde que un número de puerto diferente constituye un dominio diferente, que puede ser un problema. foo.com es un dominio diferente que foo.com:8080
RyBolt
2
Me salvas la vida;)
Paweł Groński
26

La respuesta de @ Mihai-Andrei Dinculescu es correcta, pero para beneficio de los buscadores, también hay un punto sutil que puede causar este error.

Agregar un '/' al final de su URL evitará que EnableCors funcione en todos los casos (por ejemplo, desde la página de inicio).

Es decir, esto no funcionará

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

pero esto funcionará:

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

El efecto es el mismo si se usa el atributo EnableCors.

HockeyJ
fuente
¡¡Gracias!! Fue útil.
Ankit Sahrawat
23

Seguí todos los pasos anteriores indicados por Mihai-Andrei Dinculescu .
Pero en mi caso, necesitaba 1 paso más porque las OPCIONES http estaban deshabilitadas en la Web. Configure por la línea de abajo.

<remove name="OPTIONSVerbHandler" />

Lo acabo de eliminar de Web.Config (solo coméntelo como se muestra a continuación) y Cors funciona de maravilla

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

Puede ser debido a la instalación de paquetes Nuget de Cors.

Si enfrenta el problema después de instalar y deshabilitar cors de nuget, puede intentar reinstalar la API web.

Desde el administrador de paquetes, ejecute Update-Package Microsoft.AspNet.WebApi -reinstall

Bimal Das
fuente
Esto fue exactamente para mí. Instalé System.Web.Http.Cors y luego lo desinstalé, lo que dejó a WebApi en la versión incorrecta (recientemente actualizada) entre 5.2.2 y 5.2.3
TaeKwonJoe
7

Pruebe esto para asegurarse de haber configurado CORS correctamente:

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

¿Sigue sin funcionar? Verifique la presencia de encabezados HTTP.

Andrei
fuente
para comprobar si su trabajo, es mejor eliminar supportCredentials así, lo hace coros desactivar en ciertas condiciones
harishr
La mejor respuesta porque no quiero habilitar CORS para todo mi sitio, solo ciertos puntos finales. config.EnableCors()es necesario para esto también.
Csaba Toth
4

Para que cualquier protocolo CORS funcione, debe tener un método OPTIONS en cada punto final (o un filtro global con este método) que devolverá esos encabezados:

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

La razón es que el navegador enviará primero una solicitud de OPCIONES para 'probar' su servidor y ver las autorizaciones

sam
fuente
2

Entiendo el siguiente caso sobre cors. Tal vez sea útil para alguien. Si agrega la función 'WebDav Redirector' a su servidor, las solicitudes PUT y DELETE fallarán.

Por lo tanto, deberá eliminar 'WebDAVModule' de su servidor IIS:

  • "En la configuración de los módulos IIS, conecte el WebDAVModule, si su servidor web lo tiene, luego quítelo".

O agregue a su configuración:

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

Andrey R
fuente
2

Sé que voy a llegar muy tarde. Sin embargo, para cualquiera que esté buscando, pensé en publicar lo que FINALMENTE funcionó para mí. No digo que sea la mejor solución, solo que funcionó.

Nuestro servicio WebApi utiliza el método config.EnableCors (corsAttribute). Sin embargo, incluso con eso, todavía fallaría en las solicitudes previas al vuelo. La respuesta de @ Mihai-Andrei Dinculescu me dio la pista. En primer lugar, agregué su código Application_BeginRequest () para vaciar las solicitudes de opciones. Eso TODAVÍA no funcionó para mí. El problema es que WebAPI todavía no estaba agregando ninguno de los encabezados esperados a la solicitud de OPCIONES. Lavarlo solo no funcionó, pero me dio una idea. Agregué los encabezados personalizados que de otro modo se agregarían a través de web.config a la respuesta a la solicitud de OPCIONES. Aquí está mi 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, esto solo se aplica a las solicitudes de OPCIONES. Todos los demás verbos son manejados por la configuración CORS. Si hay un mejor enfoque para esto, soy todo oídos. Me parece una trampa y preferiría que los encabezados se agregaran automáticamente, pero esto es lo que finalmente funcionó y me permitió seguir adelante.

John Groft
fuente
1

La respuesta de @ Mihai-Andrei Dinculescu funcionó para mí, por ejemplo:

  • Agregar un <httpProtocol>en la <system.webServer>sección web.config
  • Devolución de respuesta vacía para OPTIONSsolicitudes a través de lo mencionado Application_BeginRequest()englobal.asax

Excepto que su cheque Request.Headers.AllKeys.Contains("Origin")NO funcionó para mí, porque la solicitud contenía un origing, así que en minúsculas. Creo que mi navegador (Chrome) lo envía así para solicitudes CORS.

Resolví esto un poco más genéricamente usando una variante de su Containscheque que no distingue entre mayúsculas y minúsculas : if (culture.CompareInfo.IndexOf(string.Join(",", Request.Headers.AllKeys), "Origin", CompareOptions.IgnoreCase) >= 0) {

Bart
fuente
0

Si tiene seguridad \ requestFiltering nodos en su web.config de la siguiente manera:

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

asegúrese de agregar esto también

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

Había intentado todo lo que pude encontrar en la red, incluidos los métodos que se dieron en esta respuesta. Después de casi tratar de resolver el problema durante todo el día, he encontrado la solución que me ha funcionado de maravilla.

en el archivo WebApiConfig en la carpeta App_Start , comente todas las líneas de código y agregue el siguiente 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
fuente
0

Sé que la gente probablemente encontrará esto muy obvio al principio, pero realmente piense en esto. Esto a menudo puede suceder si has hecho algo mal.

Por ejemplo, tuve este problema porque no agregué una entrada de host a mi archivo de hosts. El verdadero problema era la resolución de DNS. O acabo de obtener la URL base incorrecta.

A veces recibo este error si el token de identidad proviene de un servidor, pero estoy tratando de usarlo en otro.

A veces obtendrá este error si tiene el recurso incorrecto.

Puede obtener esto si coloca el middleware CORS demasiado tarde en la cadena.

Bluebaron
fuente
0

Evite la habilitación de múltiples lugares CORS, como WebApiCOnfig.cs, el método GrantResourceOwnerCredentials en el proveedor y el atributo de encabezado del controlador, etc.

  1. Web que tiene truble en la interacción con DB que usaste.
  2. AWS Cloud Si VPC de Web API y DB son diferentes.

El siguiente código es más que suficiente para corregir el origen de permitir el control de acceso. // Asegúrese de que app.UseCors debe estar en la parte superior de la línea de código de configuración.

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

Esto ralentizó mi problema.

Sharad
fuente
0

Ese problema ocurre cuando intenta acceder desde un dominio diferente o un puerto diferente.

Si está utilizando Visual Studio, vaya a Herramientas> Administrador de paquetes NuGet> Consola del Administrador de paquetes. Allí debe instalar el paquete NuGet Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

Luego, en PROJECT> App_Start> WebApiConfig, habilite 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:"*"));

        ....

    }
}

Una vez instalado con éxito, cree la solución y eso debería ser suficiente

Tiago Martins Peres 李大仁
fuente