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 bewusst sind. Ich habe Chrome und Firefox verwendet, um die Website zu durchsuchen. Ich habe mit Fiddler getestet und alle Antworten scheinen auf dem Geld zu sein.
Jetzt schreibe ich eine einfache Test.aspx, um diese neue Web-API zu verwenden. 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-Methode zurück, die nicht zulässig ist.
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 standardmäßig nicht in Web-API-Controllern verkabelt 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 Fehler 405 Method Not Allowed, 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 man die Options-Methode richtig codiert oder ob der Controller überhaupt der richtige Ort ist, um den Code einzufügen. Seltsam (für mich), dass die Web-API-Site bei Betrachtung von Firefox oder Chrome richtig reagiert, der obige .ajax-Aufruf jedoch Fehler ausgibt. Wie gehe ich mit der "Preflight" -Prüfung im .ajax-Code um? Vielleicht sollte ich dieses Problem in der .ajax-Logik der Client-Seite ansprechen? 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 habe gesucht, aber keine Antworten gefunden, die geholfen haben.
UPDATE IMHO, dies ist ein clientseitiges Problem und hat mit dem obigen Ajax JQuery-Code zu tun. Ich sage dies, weil Fiddler keine 405-Fehlerheader anzeigt, wenn ich über einen Webbrowser auf mywebapidomain / api / user zugreife. Der einzige Ort, an dem ich dieses Problem duplizieren kann, ist der Aufruf von JQuery .ajax (). Der oben genannte identische Ajax-Aufruf funktioniert auch einwandfrei, wenn er auf dem Server (derselben Domäne) ausgeführt wird.
Ich habe einen anderen Beitrag gefunden: Prototyp-AJAX-Anfrage wird als OPTIONS anstatt als GET gesendet; führt zu 501 Fehlern , die verwandt zu sein scheinen, aber ich habe an ihren Vorschlägen ohne Erfolg herumgebastelt. Anscheinend ist JQuery so codiert, dass, wenn eine Ajax-Anfrage domänenübergreifend ist (was meine ist), ein paar Header hinzugefügt werden, 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 ändern ...
Bei der folgenden Antwort wird davon ausgegangen, dass es sich um ein serverseitiges Problem handelt. Vielleicht, denke ich, aber ich neige mich zum Kunden und es wird nicht helfen, einen Hosting-Anbieter anzurufen.
quelle
Antworten:
Wie Daniel A. White in seinem Kommentar sagte, wird die OPTIONS-Anforderung höchstwahrscheinlich vom Client als Teil einer domänenübergreifenden JavaScript-Anforderung erstellt. Dies erfolgt automatisch durch CORS-kompatible Browser (Cross Origin Resource Sharing). Die Anfrage ist eine vorläufige Anfrage oder eine Anfrage vor dem Flug , die vor der eigentlichen AJAX-Anfrage gestellt wird, um zu bestimmen, welche Anforderungsverben und -header für CORS unterstützt werden. Der Server kann wählen, ob er keine, alle oder einige der HTTP-Verben unterstützt.
Um das Bild zu vervollständigen, verfügt die AJAX-Anforderung über einen zusätzlichen "Origin" -Header, der angibt, woher die ursprüngliche Seite stammt, auf der sich das JavaScript befindet. Der Server kann wählen, ob Anforderungen von einem beliebigen Ursprung oder nur für eine Reihe bekannter, vertrauenswürdiger Ursprünge unterstützt werden sollen. Das Zulassen eines Ursprungs ist ein Sicherheitsrisiko, da dies das Risiko einer Cross Site Request Forgery (CSRF) erhöhen kann.
Sie müssen also CORS aktivieren.
Hier ist ein Link, der erklärt, wie dies in der ASP.Net-Web-API gemacht wird
http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors
Mit der dort beschriebenen Implementierung können Sie unter anderem angeben
Im Allgemeinen funktioniert dies einwandfrei, Sie müssen jedoch sicherstellen, dass Sie sich der Sicherheitsrisiken bewusst sind, insbesondere wenn Sie Cross-Origin-Anforderungen von einer beliebigen Domain zulassen. Überlegen Sie genau, bevor Sie dies zulassen.
In Bezug darauf, welche Browser CORS unterstützen, sagt Wikipedia, dass die folgenden Engines dies unterstützen:
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing#Browser_support
quelle
Die Antwort von Mike Goodwin ist großartig, aber als ich sie ausprobierte, schien sie auf MVC5 / WebApi 2.1 ausgerichtet zu sein. Die Abhängigkeiten für Microsoft.AspNet.WebApi.Cors haben mit meinem MVC4-Projekt nicht gut funktioniert.
Der einfachste Weg, CORS auf WebApi mit MVC4 zu aktivieren, war der folgende.
Beachten Sie, dass ich alle zugelassen habe. Ich schlage vor, dass Sie die Origin nur auf die Clients beschränken, für die Ihre API bereitgestellt werden soll. Alles 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 }; } }
quelle
Fügen Sie dies einfach Ihrer
Application_OnBeginRequest
Methode hinzu (dies aktiviert die CORS-Unterstützung global für Ihre Anwendung) und "bearbeiten" Sie Preflight-Anforderungen: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-Anforderungen von überall an Ihren Server ermöglicht (Sie können stattdessen nur eine durch Kommas getrennte Liste von Ursprüngen / URLs zulassen, wenn Sie dies bevorzugen).
Ich habe stattdessen den aktuellen Client-Ursprung verwendet,
*
da dies Anmeldeinformationen ermöglicht => Die EinstellungAccess-Control-Allow-Credentials
auf true ermöglicht die browserübergreifende SitzungsverwaltungAußerdem müssen Sie die Verben zum Löschen und Einfügen, Patchen und Optionen in Ihrem
webconfig
Abschnitt aktivierensystem.webServer
, andernfalls 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
quelle
Application_OnBeginRequest
hat mir geholfen. Aber wenn Sie wollen in der Lage sein , Daten zu mit Genehmigung zu erhalten, sollten Sie auch hinzufügenAuthorization
zuAccess-Control-Allow-Headers
Nachdem ich in einem Web-API-2-Projekt auf dasselbe Problem gestoßen war (und die Standard-CORS-Pakete aus Gründen, die hier nicht behandelt werden sollten, nicht verwenden konnte), konnte ich dieses Problem beheben, indem ich einen benutzerdefinierten DelagatingHandler implementierte:
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 bei einigen anderen hier veröffentlichten 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 keine MVC enthält, sondern nur die Web-API 2.
quelle
Ich habe es geschafft, 405- und 404-Fehler zu überwinden, die bei Ajax-Optionsanfragen vor dem Flug nur durch benutzerdefinierten Code in global.asax ausgelöst wurden
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: Berücksichtigen Sie Sicherheitsprobleme, wenn Sie alles zulassen *.
Ich musste CORS deaktivieren, da der Header 'Access-Control-Allow-Origin' mehrere Werte enthält.
Auch benötigt dies in 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>
Und app.pool muss auf den integrierten Modus eingestellt sein.
quelle
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 Anforderung vor dem Flug aus. Ich habe das gefunden:
Von dieser Seite: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api (unter "Preflight-Anfragen")
quelle
In ASP.NET Web API 2 wurde CORS-Unterstützung hinzugefügt. Bitte überprüfen Sie den Link [ http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api ]
quelle
protected void Application_EndRequest() { if (Context.Response.StatusCode == 405 && Context.Request.HttpMethod == "OPTIONS" ) { Response.Clear(); Response.StatusCode = 200; Response.End(); } }
quelle
Auch ich stand vor dem gleichen Problem.
Führen Sie die folgenden Schritte aus, um das Problem mit der CORS-Konformität in Browsern zu beheben.
Nehmen Sie REDRock mit der Cors-Referenz in Ihre Lösung auf. Fügen Sie einen WebActivatorEx-Verweis auf die Web-API-Lösung hinzu.
Fügen Sie dann die Datei CorsConfig im Ordner Web API App_Start 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.
quelle
Ich hatte das gleiche Problem und habe es so behoben:
Wirf dies einfach in deine web.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>
quelle
//In the Application_OnBeginRequest method in GLOBAL.ASX add the following:- var res = HttpContext.Current.Response; var req = HttpContext.Current.Request; res.AppendHeader("Access-Control-Allow-Origin", "*"); res.AppendHeader("Access-Control-Allow-Credentials", "true"); res.AppendHeader("Access-Control-Allow-Headers", "Authorization"); 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(); } //Remove any entries in the custom headers as this will throw an error that there's to //many values in the header. <httpProtocol> <customHeaders> </customHeaders> </httpProtocol>
quelle