web-dev-qa-db-fra.com

Activer CORS dans Web API 2

J'ai le client et un serveur fonctionnant sur différents ports. Le serveur exécute Web API 2 (v5.0.0-rc1) .

J'ai essayé d'installer package de prise en charge d'origine croisée de l'API Web de Microsoft ASP.NET et de l'activer dans WebApiConfig.cs. Cela me donne la fonction EnableCors(), donc le paquet a été installé correctement.

Ici vous pouvez voir ma fonction Register() dans WebApiConfig.cs:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    var cors = new EnableCorsAttribute("*", "*", "*");
    config.EnableCors(cors);
}

GET les requêtes fonctionnent correctement. Mais lors de l'envoi de POST, j'obtiens ce qui suit:

OPTIONS http://localhost:19357/api/v1/rooms? 404 (Not Found) angular.js:10159
OPTIONS http://localhost:19357/api/v1/rooms? Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin. angular.js:10159
XMLHttpRequest cannot load http://localhost:19357/api/v1/rooms. Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.

Selon Fiddler, il n'envoie que la requête OPTIONS. Il n'émet pas le POST après.

Donc, je suppose que la config.EnableCors(cors); du WebApiConfig.cs Ne fait rien, ce qui amène le serveur à refuser au client/navigateur d'envoyer une demande POST.

Avez-vous une idée de la façon de résoudre ce problème?

EDIT 05.09.13 Ceci a été corrigé dans 5.0.0-rtm-130905

54
Gaui

Je frappe très certainement ce problème avec le routage d'attribut. Le problème était corrigé à partir de 5.0.0-rtm-130905. Mais vous pouvez quand même essayer les versions nocturnes qui auront très certainement la solution.

Pour ajouter des nightlies à votre source de paquets NuGet, allez à Tools -> Library Package Manager -> Package Manager Settings et ajoutez l’URL suivante sous Package Sources: http://myget.org/F/aspnetwebstacknightly

6
Gaui

CORS fonctionne parfaitement bien en Microsoft.AspNet.WebApi.Cors version 5.2.2. Les étapes suivantes ont configuré CORS comme un charme pour moi:

  1. Install-Package Microsoft.AspNet.WebApi.Cors -Version "5.2.2" // exécuté à partir de la console du gestionnaire de packages
  2. Dans Global.asax, ajoutez la ligne suivante: AVANT TOUT ENREGISTREMENT DE ROUTE MVC

    GlobalConfiguration.Configure(WebApiConfig.Register);
    
  3. Dans la méthode WebApiConfig Register, utilisez le code suivant:

    public static void Register(HttpConfiguration config)
    {
        config.EnableCors();
        config.MapHttpAttributeRoutes();
    }
    

Dans le fichier web.config, le gestionnaire suivant doit être le premier du pipeline:

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Dans le contrôleur dérivé de ApiController, ajoutez le EnableCorsAttribute:

[EnableCors(origins: "*", headers: "*", methods: "*")] // tune to your needs
[RoutePrefix("")]
public class MyController : ApiController

Cela devrait vous mettre en place bien!

55
Sudhanshu Mishra

Je n'ai pas eu besoin d'installer de paquet. Un simple changement dans le fichier web.config de votre projet WebAPI fonctionne très bien:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

Le crédit va à: tilisation de CORS dans ASP.NET WebAPI sans être un scientifique expérimenté

34
Mosharaf Hossain

Assurez-vous que vous accédez à l'API Web via HTTPS.

J'active également cors dans WebApi.config.

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

Mais ma demande CORS n'a pas fonctionné jusqu'à ce que j'utilise les URL HTTPS.

5
tno2007

Réponse tardive pour référence future. Ce qui fonctionnait pour moi, c’était de l’activer avec nuget, puis d’ajouter des en-têtes personnalisés dans web.config.

4
Mariusz

Pour référence, utiliser l’approche [EnableCors()] ne fonctionnera pas si vous interceptez le pipeline de messages à l’aide d’un DelegatingHandler. Dans mon cas, recherchait un en-tête Authorization dans la demande et le traitait en conséquence avant même que le routage ne soit appelé, ce qui signifiait que ma demande était traitée plus tôt dans le pipeline, de sorte que la [EnableCors()] n'avait pas effet.

En fin de compte trouvé un exemple CrossDomainHandler class (crédit à shaunx pour le Gist ) qui gère le CORS pour moi dans le pipeline et l’utilise est aussi simple que d’ajouter un autre gestionnaire de messages au pipeline.

public class CrossDomainHandler : DelegatingHandler
    {
        const string Origin = "Origin";
        const string AccessControlRequestMethod = "Access-Control-Request-Method";
        const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
        const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
        const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
        const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            bool isCorsRequest = request.Headers.Contains(Origin);
            bool isPreflightRequest = request.Method == HttpMethod.Options;
            if (isCorsRequest)
            {
                if (isPreflightRequest)
                {
                    return Task.Factory.StartNew(() =>
                    {
                        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
                        response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());

                        string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
                        if (accessControlRequestMethod != null)
                        {
                            response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
                        }

                        string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
                        if (!string.IsNullOrEmpty(requestedHeaders))
                        {
                            response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
                        }

                        return response;
                    }, cancellationToken);
                }
                else
                {
                    return base.SendAsync(request, cancellationToken).ContinueWith(t =>
                    {
                        HttpResponseMessage resp = t.Result;
                        resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
                        return resp;
                    });
                }
            }
            else
            {
                return base.SendAsync(request, cancellationToken);
            }
        }
    }

Pour l'utiliser, ajoutez-le à la liste des gestionnaires de messages enregistrés.

config.MessageHandlers.Add(new CrossDomainHandler());

Toutes les demandes de contrôle en amont par le navigateur sont traitées et transmises, ce qui signifie que je n'ai pas eu besoin de mettre en œuvre un [HttpOptions]IHttpActionResult sur le contrôleur.

4
Lankymart
 var cors = new EnableCorsAttribute("*","*","*");
 config.EnableCors(cors);

 var constraints = new {httpMethod = new HttpMethodConstraint(HttpMethod.Options)};
 config.Routes.IgnoreRoute("OPTIONS", "*pathInfo",constraints);
3
Vikas