[client: Angular 6][server: nodejs, typescript-rest] einfaches post zum server scheitert

T

Tersus

Gast
Mahlzeit,

ich habe einen Angular 6 Client gebaut und einen NodeJs Server mit Typescript bzw. dem npm package typescript-rest.

Es ist wichtig zu wissen, dass Client und Server auf der selben Maschine laufen und ich somit womöglich CORS benötige.

Hier der wichtige Teil des primitiven Servlets meines Servers :

Javascript:
...
  @Path(RestControllerPath.Model)
  @POST
  receive(model: any, @ContextResponse response: express.Response): void {

    // Keine Ahnung, ob diese headers notwenig sind.
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

    console.debug("json", model); // Server soll erstmal nur das vom Client erhaltene Model ausgeben.
  }
...

Hier nun der wichtige Part des Clients:

Javascript:
...
    request() {
        const o = new Object();
        o['a'] = "A";
        o['b'] = 5;

        let myHeaders = new HttpHeaders();
        myHeaders = myHeaders.append("Content-Type", "application/json; charset=utf-8");
        const httpOptions = { headers: myHeaders };
        const url = ... // uninteressant
        this.httpClient.post(url, o, httpOptions).subscribe(
            (suc: any) => {
                console.debug("http request for " + url + ":", suc);
            },
            (error: any) => {
                console.error("error http request for " + url + ":", error);
            }
        );
    }
...

Sobald der Request an an server geht, meldet der Server einen MethodNotAllowedError: Method Not Allowed und liefert einen 405 zurück.

Im Chromium sind folgende Infos zum Request gelistet:

Response Header
Code:
HTTP/1.1 405 Method Not Allowed
X-Powered-By: Express
Allow: POST
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 1452
Date: Fri, 26 Oct 2018 12:19:31 GMT
Connection: keep-alive

Request Header
Code:
OPTIONS /rc/model HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7

Auffallend am Request Header ist, dass Angular meinen Content-Type gar nicht gesetzt hat, obwohl korrekt im Code umgesetzt.

Ich bin langsam mit meinem Latein am Ende. Kann mir einer von euch weiter helfen?
 
Hi,

In deinem Request-Header steht, dass die Method nicht POST sondern OPTIONS ist.
Dein NestJS läuft auf einem Anderen Port als dein Angular gehostet wird (ich nehme an es geht und den Dev-Server via ng serve? Dann ist der Request vermutlich ein sogenannter preflight request, der dann fehlschlägt.
https://stackoverflow.com/questions...uest-sending-the-options-verb-instead-of-post
Hast du eine Proxy config im Angular Part? Die kann für dich das redirecten auf das Backend übernehmen.
Bei uns ist das z.B.:
proxy.conf.json
JSON:
{
  "/api": {
    "target": "http://localhost:5000",
    "secure": false
  }
}
Da musst du natürlich den Port vom NestJS-Webserver eintragen.
Starten kannst du es dann über ng serve --proxy-config proxy.conf.json.

Viel Erfolg :)
 
Es wird ein sogenannter Preflight Request gesendet (Method: OPTIONS), wenn deine POST Request kein "simpler" Request ist. Siehe dazu: CORS Preflight

Also irgendwas führt dazu das ein Preflight Request notwendig ist, also Headers und co mal prüfen. Dein Node-Server antwortet außerdem nicht auf die OPTIONS Methode.

Du hast also 2 Optionen:
1. dein POST muss konform sein mit einem simplen Request oder
2. dein Node-Server muss korrekt auf Preflight-Requests antworten (OPTIONS)
 
Danke Jungs! Das war's gewesen!

Eine Lösung ist halt, den Preflight-Requests zu konfigurieren.

Hier entsprechend der Code für das typescript-rest framework.

Javascript:
...
  @Path(RestControllerPath.Model)
  @OPTIONS // <-- Preflight-Requests
  requestOptions(@ContextResponse response: express.Response): string {

    response.setHeader("Access-Control-Allow-Origin", "*"); // Alle quellen erlauben (nicht sinnvoll)
    // restliche Header sind selbsterklärend
    response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

  }
...
 
Zurück
Oben