# AJAX/RestController Post Problem



## Sternenregen (12. Sep 2020)

Grüße euch,

Ich bin hart genervt. Sitze seit über 8 Stunden ab den Mist und ich komm nicht weiter. Ich hab schon so viele Dinge probiert, dass ich das hier gar nicht alles aufzählen kann. Es ist bestimmt irgend ein grundlegender Fehler.

Ich will über ein HTML Dokument ein AJAX Skript aufrufen, dass einen simplen String an einen Restcontroller @POST/PUT schicken soll. Der entsprechende Methode wird auch getriggert, allerdings ist der übergebene String IMMER null. Ich habe Postman genommen. Dort kommt der String an und wird verarbeitet. Das sagt mir, dass es am AJAX Script bzw dem HTML Teil liegt.

Die Forms performen ja in der Regel nur ein GET und kein POST. Daran wirds irgendwie liegen. Aber ich weiß nicht mehr weiter. Hab komplett Google umgegraben. Ich habe viele LÖsungen gefunden. Muss gestehen, ich arbeite jetzt das erste mal mit AJAX bzw Javascript im Allgemeinen so richtig.


Zur Erklärung: "operator" ist der Parameter der in dem RestController erwartet wird.



Hier die AJAX Function und der HTML Teil. Der RestController tut was er soll.



Und hier der relevante HTML Teil:


```
<div id="formDiv">
        <form id="form" method="post">
            <input type="text" id="display">
           
                <div class="batteryBlock">      
                    <table>
                        <tr>                          
                            <td><button type="submit" onClick="test()" id="bat" class="btnNum"  value = "+">+</button></td>          
                        </tr>
```






Erlöst mich bitte.


----------



## Thallius (12. Sep 2020)

mach mal Type=„Button“. ehrlich gesagt habe ich keine Ahnung was passiert wenn du submit und onClick gleichzeitig benutzt aber der submit müßte eigentlich einen Page reload Auslösen was sicherlich nicht gewollt ist


----------



## mrBrown (13. Sep 2020)

Der content-type sieht zumindest schräg aus, was sendet der Browser da denn genau?


----------



## Sternenregen (13. Sep 2020)

Selbst von diesem AJAX-Script, hatte ich schon unzählige Versionen davon. Meine Content-Types u.a.  so aus:   text/plain, text, 'application/x-www-form-urlencoded'
usw... Und sogar laut Dokumentation komplett weggelassen, da letzteres eigentlich auch der default Wert ist.

Hab aber mal einen Script Validator drüberlaufen lassen, der monierte da @action("url...."). Hab jetzt nur   url: "localhost:8080" dortstehen.



> Der content-type sieht zumindest schräg aus, was sendet der Browser da denn genau?



Ich habe einen RestController. In meinem speziellen POST Methode gibt es keinen Pfad sondern nur ein Parameter der verlangt wird. Wenn ich es nicht verwechsel (Hab in dem Gebiet erst vor 4 Tagen begonnen) ist es ja glaub ich da der Vorteil dass die URL gleich bleibt.

Ich hoffe es gibt vom Ergebnis einen Unterschied zwischen

```
var muell = { "operator": "umpalumpa" }
```
und

```
data: {"operator": "umpalumpa"},
```
Was ich bisher gelesen habe, ist der erste Wert, der Parametername und der zweite (umpalumpa), der Wert, der darin gespeichert werden soll.
Falls dem nicht so ist, hab ich den Fehler gefunden. Weil ansonsten wird ja nur das object ausgegeben und ich müsste es ähnlich wie bei JSON stringifyen  Aber da der DataType nur "text" ist...


Wie kann ich denn testen was bei einem ajax-Script versendet wird? Hab versucht in das Script sowie in der Success bzw Error ein Alert einzubauen. Aber das wird nicht aufgerufen. Das sagt mir eigentlich dass der Fehler vor dem Success: sein muss. Aber wie gesagt. ich hab schon alles erdenkliche ausprobiert.

Trotz allen hab ich das data: im Verdacht.


----------



## sascha-sphw (13. Sep 2020)

Den Request kannst Du Dir im Browser in den Dev-Tools Anschauen. F12 (Chrome, Firefox, IE, Edge) da findest Du dann einen Bereich in dem die ganzen Requests angezeigt werden. HINT: erst Dev-Tools öffnen, dann Request absetzen.

Wie erwartest Du denn die Daten am RestController? Passend dazu musst Du sie über JS abschicken.


----------



## sascha-sphw (13. Sep 2020)

Über Insomnia kann man sich das JavaScript eines Requests generieren lassen. Ich kann mir gut vorstellen, dass Postman das auch kann.


----------



## Sternenregen (13. Sep 2020)

> Wie erwartest Du denn die Daten am RestController? Passend dazu musst Du sie über JS abschicken.


Der RestController erwartet an der Stelle einen String.

So sieht der Methodenkopf aus:

```
public String setTest(@RequestParam(required=false) String operator)
```

Ich hab jetzt mal in Chrome nachgeschaut. Die Request Methode ist auf jeden Fall POST. Aber die Content-Länge ist 0. Sowohl beim Request wie auch bei der Response. Aber das zeigt mir auch die JavaConsole an, dass der String null ist.

Die Frage ist warum.

Achja und Postman hab ich schon genutzt. Das Post funktioniert und die Werte werden auch übertragen. Das sagt mir persönlich, dass das Problem bei dem data: liegt bzw an der Stelle, wo in dem AJAX der Text übergeben wird.

Aktuell sieht das Skript so aus:



```
function test(){
        
        alert("springe in ajax funktion");   
        
         $.ajax({
                url: "localhost:8080",
                type: "POST",
                dataType: 'text',
                data: { 'operator': 'foooooo'},
                cache: false,
                              
                success: function (data) {                   //Springt nicht rein
                    alert("Es funktioniert endlich");
                },
              
                error: function(data){                       //Springt nicht rein
                    alert("Es geht nicht, aber es läuft");
                }
            });   
        
         alert("muh");                                      //Springt nicht rein
    }
```


----------



## Thallius (13. Sep 2020)

Also für mich ist das kein String sondern ein JSON. Von daher würde ich es ganz blöd mal mit datatype: "json" probieren. Weiterhin finde ich es befremdlich, dass die URL der Root ist. Normalerweise nimmt man hier eine URL die den Namen der API Methode enthält. Also Localhost:8080/setUser oder sowas. Weiterhin adde doch mal


```
.done(function() { console.log("Done"); } );
```

zum request hinzu. Vielleicht wird das ja aufgerufen


----------



## mrBrown (13. Sep 2020)

Thallius hat gesagt.:


> Also für mich ist das kein String sondern ein JSON. Von daher würde ich es ganz blöd mal mit datatype: "json" probieren.


dataType ist der Typ, den man vom Server zurück bekommt. Ist in diesem Fall String, text  ist also völlig richtig.




Thallius hat gesagt.:


> Weiterhin finde ich es befremdlich, dass die URL der Root ist. Normalerweise nimmt man hier eine URL die den Namen der API Methode enthält. Also Localhost:8080/setUser oder sowas


Eine Methode in der URL stehen zu haben ist eigentlich das genaue Gegenteil von üblich – das gilt bei Rest als ziemliches Antipattern.
Da der Controller auch aufgerufen wird, scheint die URL korrekt zu sein.


----------



## Sternenregen (13. Sep 2020)

OMG.

Jetzt gehts. Nach der url hat ein / gefehlt.   Also localhost:8080/.

Ich dachte immer und machte immer localhost:8080?operator=fooo

10 Stunden wegen einem Schrägstrich.

!!

Aber das Ganze offenbart mir, dass ich den Part mit dem *data: *offenbar doch nicht so ganz verstanden habe.

Es hatte jetzt funktioniert weil ich in die URL:

```
url: "localhost:8080/?operator=fooo",
```

Aber ist nicht gerade der Sinn von data: den Parameternamen und den Wert zu übermitteln? Hab es grad getestet.

```
localhost:8080/?
data: { 'operator':'foooooo'},
```

geht auch nicht. Ich hatte mir Dokumentation angeschaut und hatte das so rausgelesen.


----------



## mrBrown (13. Sep 2020)

Moment – ohne slash wird der Request zwar gesendet, aber der Body ist leer, und mit slash ist der Body dann gefüllt?


----------



## Sternenregen (13. Sep 2020)

Jap. So siehts aus.

Ich dachte die ganze Zeit

*localhost:8080?operator=fooo *           ==                * url:"localhost:8080",  data: { 'operator':'foooooo'}*

Aber beides ging nicht.
*
localhost:8080/?operator=foo* 

läuft


----------



## Sternenregen (13. Sep 2020)

Ich hab mir jetzt nochmal die offizielle Dokumentation angeschaut: https://api.jquery.com/jquery.ajax/
Ich erkenne keinen Fehler.

Laut Doku:
*data: { 'operator':'foooooo'}    =     operator=foooooo*

Gut, wenn man danach geht, fehlt ja noch das Fragezeichen. Und nimmt man noch das / dazu, müsste es ja theoretisch in der Kombination
ja hinhauen:

*localhost:8080/?
data: { 'operator':'foooooo'} *

Tut es aber nicht. Woran liegt das? Der Fehler muss daher im data: liegen. Ich will das verstehen. Weiß das jemand?


----------



## mrBrown (13. Sep 2020)

Du sendest einen POST-Request, da steht das im Body, nicht in der URL


----------



## Sternenregen (13. Sep 2020)

Ja, aber warum wird das nicht berücksichtigt?  Der RestController/POST/PUT wird ja getriggert und die Anfrage kommt an. Warum nicht der Inhalt?

Es ist wie du sagst, ein POST-Request. Und ich habe den Parameter und den Wert mit angegeben.
Das  *data: { 'operator':'foooooo'}*   müsste ja im Body stehen. Oder versteh ich das falsch.

Ich glaub das Ganze resultiert daraus, dass das GET Request eher abgefeuert wird als das AJAX. Und deswegen ist es immer null. Ich guck mal. Da gibt es ja etwas, um dieses zu unterbinden. Wenn es funzt, schreibe ich es hierher.


----------



## sascha-sphw (13. Sep 2020)

Sternenregen hat gesagt.:


> Ja, aber warum wird das nicht berücksichtigt? Der RestController/POST/PUT wird ja getriggert und die Anfrage kommt an. Warum nicht der Inhalt?


Der Inhalt kommt wahrscheinlich im Body auch an, nur wird er von Deinem Service nicht ausgewertet, die Annotation @RequestParam steht für einen Query oder einen Form Parameter. Wenn ich mich nicht irre.

Versuchs mal so:

```
$.ajax({
  "url": "http://localhost:8080/",
  "method": "POST",
  "headers": {
    "content-type": "application/x-www-form-urlencoded"
  },
  "data": {
    "operator": "fooo"
  }
}).done(function (response) {
  console.log(response);
});
```

Wenn Du den Body auswerten möchtest, sollte im Controller sowas stehen.

```
public class MyDto {
    private String operator;
   
    // getters setter omitted
}

@PostMapping
public String setTest(MyDto dto) { ... }
```

Und dann mit JS:

```
$.ajax({
  "url": "http://localhost:8080/",
  "method": "POST",
  "headers": {
    "content-type": "application/json"
  },
  "processData": false,
  "data": JSON.stringify({
      operator: "fooo"
  })
}).done(function (response) {
  console.log(response);
});
```

PS: Code nicht getestet, es könnten also Fehler enthalten sein.


----------



## sascha-sphw (13. Sep 2020)

Sternenregen hat gesagt.:


> Achja und Postman hab ich schon genutzt. Das Post funktioniert


Ja, was ich meinte, ist dass es in Postman die Möglichkeit gibt, sich von dem funktionierenden Request das jQuery Script generieren zu lassen.








						Generating client code | Postman Learning Center
					

Generating client code: documentation for Postman, the collaboration platform for API development. Create better APIs—faster.




					learning.postman.com


----------



## mrBrown (13. Sep 2020)

sascha-sphw hat gesagt.:


> Der Inhalt kommt wahrscheinlich im Body auch an, nur wird er von Deinem Service nicht ausgewertet, die Annotation @RequestParam steht für einen Query oder einen Form Parameter. Wenn ich mich nicht irre.


`application/x-www-form-urlencoded` ist der default, und zumindest in der letzten Variante hier im Thread ist nichts anderes angegeben,  es sollte also ganz normal als Form-Daten gesendet werden.


----------



## mrBrown (13. Sep 2020)

Habs grad extra getestet, dieser Request funktioniert völlig Problemlos:


```
$.ajax({
    url: "http://localhost:8080",
    type: "POST",
    data: {'operator': 'foooooo'},
    success: function (data) {
        alert("Es funktioniert endlich: " + data);
    }
});
```

Und auf Spring-Seite einfach nur ein `@PostMapping("/") @ResponseBody public String test(@RequestParam String operator)`




Sternenregen hat gesagt.:


> OMG.
> 
> Jetzt gehts. Nach der url hat ein / gefehlt. Also localhost:8080/.


Mit Chrome und jQuery 3.1.1 produzieren "http://localhost:8080" und "http://localhost:8080*/*" genau den gleichem Request, der Slash am Ende ist da völlig egal.


----------

