asp.net - tutorial - npm webserver




Wie unterstützt man HTTP OPTIONS Verb in ASP.NET MVC/WebAPI-Anwendung (7)

Die Antwort von Mike Goodwin ist großartig, aber es schien, als ob ich es ausprobiert hätte, dass es auf MVC5 / WebApi 2.1 abzielte. Die Abhängigkeiten für Microsoft.AspNet.WebApi.Cors haben nicht gut mit meinem MVC4-Projekt gespielt.

Die einfachste Möglichkeit, CORS in WebApi mit MVC4 zu aktivieren, war die folgende.

Beachten Sie, dass ich alle erlaubt habe. Ich schlage vor, dass Sie die Origins auf die Clients beschränken, die Ihre API bedienen soll. All das zuzulassen ist ein Sicherheitsrisiko.

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:

Wir tun dies, um das HTTP-Verb OPTIONS zuzulassen

 public class BaseApiController : ApiController
  {
    public HttpResponseMessage Options()
    {
      return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
  }

Ich habe eine ASP.NET-Webanwendung eingerichtet, die mit einer MVC 4 / Web API-Vorlage beginnt. Es scheint, als ob die Dinge wirklich gut funktionieren - keine Probleme, die mir bekannt sind. Ich habe Chrome und Firefox verwendet, um die Website zu durchsuchen. Ich habe mit Fiddler getestet und alle Antworten scheinen auf das Geld zu sein.

So jetzt schreibe ich eine einfache Test.aspx, um diese neue Web-API zu konsumieren. Die relevanten Teile des Skripts:

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

Dies erzeugt einen REQUEST-Header:

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

Die Web-API gibt eine 405 Method Not Allowed zurück.

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>

Ich verstehe, dass das Verb OPTIONS nicht standardmäßig in Web-API-Controllern verdrahtet ist ... Also habe ich den folgenden Code in meine UserController.cs eingefügt:

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

... und dies beseitigte den 405 Method Not Allowed Fehler, aber die Antwort ist vollständig leer - es werden keine Daten zurückgegeben:

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

Es muss zusätzliche Logik geben ... Ich weiß nicht, wie ich die Optionsmethode korrekt codiere oder ob der Controller sogar der richtige Ort ist, um den Code zu setzen. Seltsam (für mich), dass die Web-API-Site korrekt reagiert, wenn sie von Firefox oder Chrome aus betrachtet wird, doch der oben genannte .ajax-Aufruf führt zu Fehlern. Wie gehe ich mit dem Preflight-Check im .ajax-Code um? Vielleicht sollte ich dieses Problem auf der Client-Seite .jax Logik angehen? Oder, wenn dies ein Problem auf der Serverseite ist, weil das Verb OPTIONS nicht behandelt wird.

Kann jemand helfen? Dies muss ein sehr häufiges Problem sein und ich entschuldige mich, wenn es hier beantwortet wurde. Ich suchte, aber fand keine Antworten, die halfen.

UPDATE IMHO, dies ist ein Client-Problem und hat mit dem obigen Ajax JQuery-Code zu tun. Ich sage das, weil Fiddler keine 405 Fehlerheader anzeigt, wenn ich von einem Webbrowser auf mywebapidomain / api / user zugreife. Der einzige Ort, an dem ich dieses Problem reproduzieren kann, ist der Aufruf von JQuery .ajax (). Der oben beschriebene identische Ajax-Aufruf funktioniert auch, wenn er auf dem Server ausgeführt wird (dieselbe Domäne).

Ich habe einen anderen Beitrag gefunden: Prototyp-AJAX-Anfrage wird als OPTIONS anstatt als GET gesendet; Ergebnisse in 501 Fehler , die verwandt zu sein scheinen, aber ich habe mit ihren Vorschlägen ohne Erfolg gebastelt. Anscheinend ist JQuery so codiert, dass wenn eine Ajax-Anfrage domänenübergreifend ist (was meine ist), sie einige Header hinzufügt, die den OPTIONS-Header irgendwie auslösen.

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

Es scheint nur, dass es eine bessere Lösung geben sollte, als den Kerncode in JQuery zu modifizieren ...

Die folgende Antwort geht davon aus, dass es sich um ein serverseitiges Problem handelt. Vielleicht, schätze ich, aber ich lehne mich dem Kunden zu, und das Anrufen eines Hosting-Anbieters wird nicht helfen.


Fügen Sie dies einfach zu Ihrer Application_OnBeginRequest Methode hinzu (dies ermöglicht die globale Unterstützung von CORS für Ihre Anwendung) und bearbeiten Sie Preflight-Anfragen:

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

* Sicherheit: Beachten Sie, dass dies Ajax-Anfragen von überall auf Ihrem Server ermöglicht (Sie können stattdessen nur eine kommagetrennte Liste von Origins / URLs zulassen, wenn Sie dies bevorzugen).

Ich habe den aktuellen Client-Ursprung anstelle von * da dies die Berechtigung credentials => erlaubt, indem Access-Control-Allow-Credentials auf true gesetzt wird, um das Cross-Browser-Session-Management zu ermöglichen

Außerdem müssen Sie delete und put, patch und options in Ihrem webconfig section system.webServer , sonst blockiert IIS sie:

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

hoffe das hilft


Ich hatte auch das gleiche Problem.

Befolgen Sie den folgenden Schritt, um das Problem der (CORS-) Kompatibilität in Browsern zu lösen.

Fügen Sie REDRock in Ihre Lösung mit der Cors-Referenz ein. Fügen Sie den WebActivatorEx-Verweis auf die Web-API-Lösung ein.

Fügen Sie dann die Datei CorsConfig im Web-API-App_Start-Ordner hinzu.

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

Mit diesen Änderungen konnte ich in allen Browsern auf das Webapi zugreifen.


Ich hatte das gleiche Problem. Für mich bestand die Lösung darin, den benutzerdefinierten Inhaltstyp aus dem jQuery AJAX-Aufruf zu entfernen. Benutzerdefinierte Inhaltstypen lösen die Pre-Flight-Anforderung aus. Ich habe das gefunden:

Der Browser kann die Preflight-Anfrage überspringen, wenn folgende Bedingungen zutreffen:

Die Anforderungsmethode ist GET , HEAD oder POST und

Die Anwendung legt keine Request-Header außer Accept , Accept-Language , Content-Language , Content-Type oder Last-Event-ID und fest

Der Content-Type Header (falls festgelegt) ist einer der folgenden:

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

Von dieser Seite: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api (unter "Preflight Requests")



Nachdem ich in einem Web-API-2-Projekt auf dasselbe Problem gestoßen bin (und die Standard-CORS-Pakete aus Gründen, auf die ich hier nicht näher eingehen möchte, nicht verwenden konnte), konnte ich dies durch Implementierung eines benutzerdefinierten DelagatingHandlers beheben:

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

Für die Web-API-Konfiguration:

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

Beachten Sie, dass ich auch die CORS-Header in Web.config aktiviert habe, ähnlich wie einige der anderen hier geposteten Antworten:

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

Beachten Sie, dass mein Projekt MVC, nur Web API 2 nicht enthält.


    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" )
        {
            Response.Clear();
            Response.StatusCode = 200;
            Response.End();
        }
    }




asp.net-web-api