Laden...

ASP.NET Core 3.0 WebApi -funktioniert im Postman aber jQuery bringt CORS Fehler

Erstellt von schuppsl vor 4 Jahren Letzter Beitrag vor 4 Jahren 3.711 Views
S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren
ASP.NET Core 3.0 WebApi -funktioniert im Postman aber jQuery bringt CORS Fehler

Hallo zusammen.

Ich habe einen einfachen Core3.0 WebService erstellt, der einen POST entgegennimmt und ein paar Daten in eine Datenbank schreibt.

Mit Postman getestet, funktioniert es prima.
Soweit schon mal gut.

Aber das Ganze soll dann in einer Stinknormalen Webanwendung (Html+JQuery) ablaufen.
Also eine einfache HTML Webseite erstellt und das bischen JavaScript Code eingebaut, anlehnend an bereits vorhandene Projektchen.

Es kommen folgende Fehlermeldungen auf der Entwicklerkonsole im Webbrowser:> Fehlermeldung:

Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
Login?ReturnUrl=%2F:1 Access to XMLHttpRequest at 'http://localhost:52373/api/SetELearnings' from origin 'https://localhost:44315' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Der JavaScript Code sieht so aus:


 <script>
     var request =
            {
         "method": "POST",
         "async": true,
         "crossDomain": true,
        "processData": false,
                "headers": {
                    "Content-Type": "application/json", 
                },
                "url":"http://localhost:52373/api/SetELearnings",
                "data": { "Modul"	: "Modulname","PersNr":"1234567","AbschlussDatum":"2014-01-01T23:28:56Z","Bemerkung":"Testeintrag" }
            }

$.ajax(request).done(function (response) {
  console.log(response);
});

    </script>

Der Controller des Webservice so:


 [Route("api/[controller]")]
    [ApiController]
    public class SetELearningsController : ControllerBase
    {
        private readonly CaptivateContext _context;

        public SetELearningsController(CaptivateContext context)
        {
            _context = context;
        }

........

 [HttpPost]
        public async Task<ActionResult<ELearning>> PostELearning(ELearning eLearning)
        {
            _context.ELearning.Add(eLearning);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetELearning", new { id = eLearning.Id }, eLearning);
        }

Ich habe schon mehrere Webservices im Einsatz, aber keiner mit Core3.0.
Also nehme ich an, dass es irgendwie daran liegen muss?

Dasselbe übrigens, wenn ich das auf dem Server im IIS veröffentliche, daher der Test erst einmal lokal.
Mit Postman geht es einwandfrei, also nehme ich an, dass es grundsätzlich funktioniert.
Selbst den Javascript Code vom Postman habe ich schon kopiert und versucht: dasselbe.

Was mache ich hier falsch?

2.207 Beiträge seit 2011
vor 4 Jahren

Hallo schuppsl,

die Fehlermeldung zeigt Richtung CORS. Wie hast du CORS konfiguriert?

Gruss

Coffeebean

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Also in der Startup.cs:


 services.AddCors(options =>
            {
                options.AddPolicy("AllowAllHeaders",
                      builder =>
                      {
                          builder.AllowAnyOrigin()
                                 .AllowAnyHeader()
                                 .AllowAnyMethod();
                      });
            });
 

und

app.UseCors("AllowAllHeaders");

Das wäre dann das nächste Problem, was zu lösen wäre.
Bei der GET Anfrage kommt kein 405, aber auch die CORS Meldung.

Also erst einmal die 405er, für die ich immer noch keine Lösung gefunden habe.

2.207 Beiträge seit 2011
vor 4 Jahren

Hallo schuppsl,

hast du die Requests mal verglichen? Gleiche Header im Postman sowie im Browser (Chrome Devtools -> Network Tab)?

Gruss

Coffeebean

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Habe mal einen anderen Aufruf versucht, mit GET:


const uri = 'http://localhost:52373/api/SetELearnings/6';

                        fetch(uri, { mode: 'cors' })
            .then(response => response.json())
  .then(data =>console.log(data))
            .catch(error => console.error('Unable to get items.', error));


Der Response Header sieht so aus

General:
Request URL:
>

Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:52373
Referrer Policy: no-referrer-when-downgrade

Request Headers:
Provisional headers are shown
Origin: null
User-Agent: *** User Agent

Der Aufruf vom Postman:



var data = null;

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "http://localhost:52373/api/SetELearnings/6");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("User-Agent", "PostmanRuntime/7.18.0");
xhr.setRequestHeader("Accept", "*/*");
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Postman-Token", "b9c8ef27-12a0-443f-9b5c-5156cd563972,039c90a0-05a9-41ea-9a23-c9f72b430835");
xhr.setRequestHeader("Host", "localhost:52373");
xhr.setRequestHeader("Accept-Encoding", "gzip, deflate");
xhr.setRequestHeader("Connection", "keep-alive");
xhr.setRequestHeader("cache-control", "no-cache");

xhr.send(data);



Der Response Header vom Postman:

Transfer-Encoding: chunked
Content-Type: application/json: charset=utf8
Server: Microsoft-IIS/10.0
x-Powered-By: ASP.NET
Date: das aktuelle Datum

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Es geht nun, ich schreibe später die Lösung hier rein.

Also eigentlich habe ich keine Ahnung, was das Problem war.
Ich vermute aber, dass es irgendwas mit https zu tun hatte, denn oben sieht man, dass immer auf https:// zugegriffen werden will.

...from origin 'https://localhost:44315' ...

Ich habe dann den WebService komplett neu erstellt, bewusst ohne https-Unterstützung.

Beim lokalen Test bin ich nach dem hier vorgegangen:
Enable Cors in ASP.NET

Ohne diese Einstellungen geht es mit dem lokalen Test (IIS Express) nicht.
Auf dem Produktiv Server (IIS) interessiert es gar nicht...

Falls es interessiert, mein Test-Javascript sieht nun so aus:

 var data =
            '{ "Modul"	: "Modulname", "PersNr":"123456789","AbschlussDatum":"2014-01-01T23:28:56Z","Bemerkung":"Testeintrag"}';
                var request =
                {
                headers: { 
                'Accept': 'application/json',
                'Content-Type': 'application/json' 
                },
            "async": true,
            "type" :"POST", 
            "url":"http://meinserver:8089/api/ELearnings",    
            "data" :data
            }
         $.ajax(request)
             .done(function (ergebnis) {
                 console.log(ergebnis);
         })
             .fail(function (errMsg) {
                 console.error(errMsg); 
         })

Vielen Dank für die Hilfe.

2.207 Beiträge seit 2011
vor 4 Jahren

Hallo schuppsl,

wieso schaust du nicht in der offiziellen Doku Enable Cross-Origin Requests (CORS) in ASP.NET Core und wieso machst du nicht alles auf https - wie allgemein empfohlen? 🤔

Dein Link ist schliesslich schon fast drei Jahre alt.

Gruss

Coffeebean

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Hi,
die Doku hatte ich schon fast komplett gelesen.
Hatte vorher aber nichts genützt.

Auf https ist bereits umgestellt!

Vielen Dank.

16.834 Beiträge seit 2008
vor 4 Jahren

bewusst ohne https-Unterstützung.

Das ist halt _bewusst _ doof / nicht die beste Idee. Das hat sein Grund, wieso Du alles - auch lokal - mit https umsetzen solltest und darauf auch das Tooling basiert bzw. dies fokussiert.
Verwende HTTPS und konfigurier CORS darauf - das ist die Best Practise und in Deiner Prod Umgebung ohnehin zwingend notwendig.

Auf dem Produktiv Server (IIS) interessiert es gar nicht...

Ob Dev oder IIS ist Cors egal. Die CORS Regeln greifen im Browser, nicht im Webserver.
CORS ist ein Standardthema und ausführlichst in den Microsoft Docs mit allen Auswirkungen beschrieben.

T
2.224 Beiträge seit 2008
vor 4 Jahren

@schuppsl
Auch solltest du deine ganzen Javascript "url" Einstellungen auf https stellen.
Aktuell sehe ich in allen JS Beispielen von dir nur die http url.
Vermutlich ist das einfach die ganze Ursache dafür, da dein Server nur HTTPS kann und deshalb reine HTTP Aufrufe eben blockt.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.834 Beiträge seit 2008
vor 4 Jahren

Vermutlich ist das einfach die ganze Ursache dafür, da dein Server nur HTTPS kann und deshalb reine HTTP Aufrufe eben blockt.

Der Server blockt hier nichts - der Client verhindert den Call.
CORS ist ein Client Thema; kein Webserver-Thema.
Cross-Origin Resource Sharing

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Ja, das was noch vor der Umstellung. Inzwischen ist das Projekt auf https, auch die ajax Aufrufe.
@Abt:
Das mit den DLL's habe ich nun im Griff (anderen Post), aber das CORS ein reines Browserthema ist, wusste ich tatsächlich nicht.
Trotzdem kann ich auf dem Server CORS aktivieren, was dann Einfluss hat...muss mich doch mal noch genauer belesen...

Zitat aus dem Wikipedia Artikel:

Ein Beispiel: Eine HTML-Seite wird von einem Server über die Domain
>
bereitgestellt. Die Seite enthält ein Script, welches eine Ressource (zum Beispiel ein Bild) nachlädt, dessen URL auf einen anderen Server verweist, bspw.
>
. Somit handelt es sich um einen Cross-Origin-Request.[2]

Wenn der Webserver hinter der zweiten Domain kein CORS unterstützt, dann verbietet er den Zugriff auf die Ressource und der Client kann darauf nicht zugreifen.

Vielen herzlichen Dank an alle.

16.834 Beiträge seit 2008
vor 4 Jahren

Trotzdem kann ich auf dem Server CORS aktivieren, was dann Einfluss hat...muss mich doch mal noch genauer belesen...

Einfach mal CORS anschauen: In jedem Response steht im Header, was der Browser machen darf, und was nicht.
Die Bezeichnung "Webserver" in dem Wikiartikel ist irreführend bzw. einfach nur sehr einfach ausgedrückt.
Ja, bei kleineren Webseiten macht das i.d.R. die Webinstanz. Bei größeren Sites nicht immer.

CORS bzw. der Header kann vom Server gesetzt werden - muss aber nicht. Das kann auch jeder andere Teilnehmer der Verbindung machen, zB. Proxies.

Wichtig ist bei CORS nur, dass es beim Client respektive dem Browser ankommt.
Im Falle von ASP.NET Core ist ASP einfach "so nett" und setzt den CORS Header - geprüft wird gar nichts, weils es in CORS vom Server nix zu prüfen gibt - nur vom Client 😉
Der Antwort liefert Regeln mit und der Client hält sich dran.

Dass Du das CORS Problem nur selbst schwer lösen kannst, wenn Du Dir gar nicht angeschaut hast was es ist oder was ASP.NET Core da macht.... ja gut äh... 😉
Das ist aber Deine Aufgabe: vorher mal das Zeug anschauen und nicht hoffen, dass das Forum Dir das beibringt.

S
schuppsl Themenstarter:in
789 Beiträge seit 2007
vor 4 Jahren

Wie immer sehr fundierte und aufschlußreiche Antwort vom Abt.
Herzlichen Dank!