Comment prendre en charge les OPTIONS HTTP ASP.NET application MVC/WebAPI

j'ai mis en place un ASP.NET application web à partir d'un modèle MVC 4/API Web. Il semble que les choses fonctionnent vraiment bien pas de problèmes que je suis au courant. J'ai utilisé Chrome et Firefox pour parcourir le site. J'ai testé avec Fiddler et toutes les réponses semblent être sur l'argent.

donc maintenant je passe à écrire un Test simple.aspx pour consommer cette nouvelle API Web. Les parties pertinentes du script:

<script type="text/javascript">
    $(function () {

        $.ajax({
            url: "http://mywebapidomain.com/api/user",
            type: "GET",
            contentType: "json",
            success: function (data) {

                $.each(data, function (index, item) {

                    ....

                    });
                }
                );

            },
            failure: function (result) {
                alert(result.d);
            },

            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("An error occurred, please try again. " + textStatus);
            }

        });

    });
</script>

En-tête de requête:

OPTIONS http://host.mywebapidomain.com/api/user HTTP/1.1
Host: host.mywebapidomain.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://mywebapidomain.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Connection: keep-alive

en l'état, L'API Web renvoie une méthode 405 non autorisée.

HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 13:28:12 GMT
Content-Length: 96

<Error><Message>The requested resource does not support http method 'OPTIONS'.</Message></Error>

je comprends que le verbe OPTIONS n'est pas câblé dans les contrôleurs D'API Web par défaut... Donc, j'ai placé le code suivant dans mon UserController.cs:

// OPTIONS http-verb handler
public HttpResponseMessage OptionsUser()
{
    var response = new HttpResponseMessage();
    response.StatusCode = HttpStatusCode.OK;
    return response;
}

...et cela a éliminé la méthode 405 erreur non autorisée, mais la réponse est complètement vide - aucune donnée n'est retournée:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 30 Sep 2013 12:56:21 GMT
Content-Length: 0

Il doit y avoir une logique supplémentaire... Je ne sais pas comment coder correctement la méthode Options ou si le controller est même l'endroit approprié pour mettre le code. Bizarre (pour moi) que le site Web API répond correctement lorsqu'il est vu à partir de Firefox ou Chrome, pourtant le .erreur d'appel ajax ci-dessus. Comment puis-je gérer la vérification "pré-vol" dans le .code ajax? Peut-être que je devrais aborder cette question du côté des clients .une logique ajax? Ou, s'il s'agit d'un problème du côté du serveur en raison de ne pas gérer le verbe OPTIONS.

est-ce que quelqu'un peut aider? Ce doit être un problème très commun et je m'excuse si la réponse est ici. J'ai cherché mais je n'ai pas trouvé de réponses qui aidaient.

mise à JOUR IMHO, il s'agit d'un problème côté client et a à voir avec le code Ajax JQuery ci-dessus. Je dis cela parce que Fiddler n'affiche aucun en-tête d'erreur 405 lorsque j'accède à mywebapidomain/api/user à partir d'un navigateur web. Le seul endroit où je peux dupliquer ce problème est à partir du JQuery .ajax() de l'appel. En outre, L'appel Ajax identique ci-dessus fonctionne très bien lorsqu'il est exécuté sur le serveur (même domaine).

j'ai trouvé un autre post: Prototype demande AJAX étant envoyé comme OPTIONS plutôt que D'obtenir; résultats dans 501 erreur qui semble être liée, mais j'ai bricolé avec leurs suggestions sans succès. Apparemment, JQuery est codé de sorte que si une requête Ajax est un domaine croisé (ce qui est le mien) il ajoute quelques en-têtes qui déclenchent l'en-tête OPTIONS. d'une certaine manière.

'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,

il semble juste qu'il devrait y avoir une meilleure solution disponible que la modification du code de base dans JQuery...

la réponse fournie ci-dessous suppose qu'il s'agit d'un problème côté serveur. Peut-être, mais je me penche vers le client et appeler un hébergeur ne va pas aider.

69
demandé sur Community 2013-09-30 17:41:12

10 réponses

comme L'a dit Daniel A. White dans son commentaire, la requête D'OPTIONS est très probablement créée par le client dans le cadre d'une requête JavaScript multi-domaines. Cela se fait automatiquement par des navigateurs conformes à la norme Cross Origin Resource Sharing (CORS). La requête est une requête préliminaire ou pre-flight , faite avant la requête AJAX réelle pour déterminer quels verbes de requête et en-têtes sont pris en charge pour CORS. Le serveur peut choisir de le prendre en charge pour none, tout ou partie du HTTP verbe.

pour compléter l'image, la requête AJAX a un en-tête" Origin " supplémentaire, qui identifie l'endroit d'où la page originale qui héberge le JavaScript a été servie. Le serveur peut choisir de prendre en charge la requête à partir de n'importe quelle origine, ou tout simplement pour un ensemble d'origines connues et fiables. Autoriser l'origine est un risque pour la sécurité, car cela peut accroître le risque de falsification de demandes (FCR).

donc, vous devez activer CORS.

Voici un lien qui explique comment faire ceci en ASP.Net API Web

http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors

l'implémentation décrite ici vous permet de spécifier, entre autres choses

  • le soutien de la SCRO sur une base par action, par le contrôleur ou l'échelle mondiale
  • pris en charge origines
  • lorsque vous activez CORS à un niveau de controller ou global, les verbes HTTP pris en charge
  • si le serveur prend en charge l'envoi de justificatifs d'identité avec des requêtes d'origine croisée

en général, cela fonctionne bien, mais vous devez vous assurer que vous êtes au courant des risques de sécurité, surtout si vous autorisez les requêtes d'origine croisée de n'importe quel domaine. Réfléchir très attentivement avant de vous le permettre.

en termes de quels navigateurs prendre en charge CORS, Wikipedia dit que les moteurs suivants le supportent:

  • Gecko 1.9.1 (FireFox 3.5)
  • WebKit (Safari 4, Chrome 3)
  • MSHTML / Trident 6 (IE10) avec support partiel en IE8 et 9
  • Presto (Opera 12)

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support

44
répondu Mike Goodwin 2013-09-30 19:08:09

la réponse de Mike Goodwin est excellente, mais il semble, quand je l'ai essayée, qu'elle visait MVC5/WebApi 2.1. Les dépendances pour Microsoft.AspNet.WebApi.Cors n'a pas bien joué avec mon projet MVC4.

la façon la plus simple d'activer CORS sur WebApi avec MVC4 était la suivante.

Notez que j'ai permis à tous, je vous suggère de limiter à l'Origine de la juste à les clients que vous voulez de votre API pour servir. Autoriser tout est un risque de sécurité.

Web.config:

<system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

BaseApiController.cs:

nous le faisons pour autoriser les OPTIONS http verb

 public class BaseApiController : ApiController
  {
    public HttpResponseMessage Options()
    {
      return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
  }
84
répondu Oliver 2014-01-30 14:14:29

il suffit d'ajouter ceci à votre méthode Application_OnBeginRequest (cela permettra au CORS de prendre en charge globalement votre application) et "gérer" les requêtes pré-vol:

var res = HttpContext.Current.Response;
var req = HttpContext.Current.Request;
res.AppendHeader("Access-Control-Allow-Origin", req.Headers["Origin"]);
res.AppendHeader("Access-Control-Allow-Credentials", "true");
res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");

// ==== Respond to the OPTIONS verb =====
if (req.HttpMethod == "OPTIONS")
{
    res.StatusCode = 200;
    res.End();
}

* sécurité: sachez que cela permettra d'activer les requêtes ajax depuis n'importe où vers votre serveur (vous pouvez à la place n'autoriser qu'une liste d'origines/URL séparées par des virgules si vous préférez).

j'ai utilisé l'origine actuelle du client au lieu de * parce que cela permettra de définir Access-Control-Allow-Credentials à true va activer la gestion de session cross browser

vous devez également activer les verbes supprimer et mettre, patch et options dans votre webconfig section system.webServer , sinon IIS les bloquera:

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

espérons que cette aide

21
répondu Chtiwi Malek 2015-10-29 07:45:46

après avoir rencontré le même problème dans un projet D'API Web 2 (et étant incapable d'utiliser les paquets standard CORS pour des raisons qui ne valent pas la peine d'être mentionnées ici), j'ai pu résoudre ce problème en implémentant un Delagatingandler personnalisé:

public class AllowOptionsHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);

        if (request.Method == HttpMethod.Options &&
            response.StatusCode == HttpStatusCode.MethodNotAllowed)
        {
            response = new HttpResponseMessage(HttpStatusCode.OK);
        }

        return response;
    }
}

pour la configuration de L'API Web:

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

notez que j'ai aussi les en-têtes CORS activés dans Web.config, similaire à certaines des autres réponses postées ici:

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule" />
  </modules>

  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, cache-control, content-type, authorization" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol>

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

notez que mon projet n'inclut pas MVC, seulement L'API Web 2.

11
répondu defines 2016-05-27 20:39:44

j'ai réussi à surmonter les erreurs 405 et 404 lancées sur les requêtes d'options ajax avant le vol seulement par le code personnalisé dans global.asax 151930920"

protected void Application_BeginRequest()
    {            
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            //These headers are handling the "pre-flight" OPTIONS call sent by the browser
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }

PS: tenir compte des problèmes de sécurité lors de l'autorisation de tout *.

j'ai dû désactiver CORS car l'en-tête 'Access-Control-Allow-Origin' contenait plusieurs valeurs.

avait aussi besoin de ça sur le web.config:

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

et app.la piscine doit être réglé sur le mode Intégré.

8
répondu lukalev 2016-09-13 14:38:27

j'ai eu ce même problème. Pour moi, la solution était de supprimer le type de contenu personnalisé de l'appel AJAX jQuery. Les types de contenu personnalisés déclenchent la demande pré-vol. J'ai trouvé ceci:

le navigateur peut sauter la demande avant le vol si les conditions suivantes sont vraies:

la méthode de requête est GET , HEAD , ou POST , et "1519190920

la demande ne définit aucun en-tête de requête autre que Accept , Accept-Language , Content-Language , Content-Type , ou Last-Event-ID , et

l'en-tête Content-Type (si elle est définie) est l'un des suivants:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

de cette page: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api (sous" demandes avant le vol")

7
répondu Dominik 2017-08-09 00:19:36

In ASP.NET Web api 2, le support CORS a été ajouté . S'il vous plaît vérifier le lien [ http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api ]

3
répondu refactor 2015-10-08 12:54:14
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.End();
        }
    }
2
répondu yongfa365 2015-09-29 09:24:11

moi aussi j'ai fait face à la même question.

suivez l'étape ci-dessous pour résoudre le problème de conformité (CORS) dans les navigateurs.

Inclure REDRock dans votre solution avec les Cors de référence. Inclure la référence WebActivatorEx à la solution D'API Web.

ajoute ensuite le fichier CorsConfig dans le dossier App_Start de L'API Web.

[assembly: PreApplicationStartMethod(typeof(WebApiNamespace.CorsConfig), "PreStart")]

namespace WebApiNamespace
{
    public static class CorsConfig
    {
        public static void PreStart()
        {
            GlobalConfiguration.Configuration.MessageHandlers.Add(new RedRocket.WebApi.Cors.CorsHandler());
        }
    }
}

grâce à ces modifications, j'ai pu accéder au webapi dans tous les navigateurs.

1
répondu Praveen Thangaraja 2014-12-09 05:50:56

j'ai eu le même problème, et c'est comme ça que je l'ai corrigé:

jetez ça sur votre toile.config:

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

    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
        <add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" />
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>

    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>
1
répondu Erti-Chris Eelmaa 2015-12-05 13:23:38