Ankündigung

Einklappen
Keine Ankündigung bisher.

Ajax Request mit JS Objekt, $_POST bleibt leer

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Ajax Request mit JS Objekt, $_POST bleibt leer

    Guten Morgen,

    ich schon wieder...

    Ich versuche einen AJAX Request mit einem Javascript Objekt abzusenden und dann in meinem PHP Backend entgegenzunehmen und entsprechend zu verarbeiten.

    Dafür nutze ich folgendes Szenario:

    index.volt (template engine, javascript ist dort mit entsprechenden Skript Tags enthalten.
    Code:
       
    ...    
    function onDragEnd() {
        this.alpha = 1;
        this.dragging = false;
        // set the interaction data to null
        this.data = null;
        ajaxWrapperPOST('/index/create', log, {x: this.x, y: this.y});
     }
    ajaxWrapper.js
    Code:
    function ajaxWrapperPOST(url, functionWhenReady, data) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                functionWhenReady(JSON.parse(this.responseText));
            }
        };
        xmlhttp.open("POST", url, true);
        xmlhttp.setRequestHeader("Content-type", "text/plain");
        xmlhttp.send(JSON.stringify(data));
    }
    
    function log(input) {
        console.log(input);
    }
    IndexController.php
    PHP-Code:
    public function createAction()
    {
        
    $this->view->disable();
        return 
    json_encode($_POST);

    Statt des erwarteten Javascript Objektes ({x: this.x, y: this.y}) ist mein $_POST Array aber leider leer.
    Der Rest an der Sache funktioniert einwandfrei, wenn ich Testweise statt $_POST als Antwort zurückzugeben einen beliebigen String verwende, wird mir in meiner Konsolenausgabe (console.log) erfolgreich der entsprechende String ausgegeben.

    Hat hier jemand eine Idee wo es hakt?
    Angemerkt sei noch in der ajaxWrapper.js hab ich auch schon den Content-type des Request Headers auf "application/json" gehabt, das hat an der Situation nichts geändert.

    Beste Grüße
    ChromOxid

  • #2
    $_POST

    Ein assoziatives Array von Variablen, die dem aktuellen Skript mittels der HTTP POST-Methode übergeben werden, wenn application/x-www-form-urlencoded oder multipart/form-data als HTTP Content-Type für die Anfrage verwendet wurde.
    Bei JSON-Text (o.ä.) brauchst du php://input => http://php.net/manual/de/wrappers.php.php

    Kommentar


    • #3
      Um das zu präzisieren: $_POST wird nur dann automatisch befüllt, wenn der Request-Body im multipart/form-data oder application/x-www-form-urlencoded Format gesendet wird. Ansonsten musst du den Body selbst parsen / dekodieren:

      PHP-Code:
      $body file_get_contents('php://input');
      $data json_decode($body); 
      Und wenn du schon zu Fuß gehst, dann schau dir doch mal Fetch API an
      [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

      Kommentar


      • #4
        Danke, hab mir schon fast gedacht, dass es sowas simples ist, funktioniert nun.


        Zitat von lottikarotti Beitrag anzeigen
        Und wenn du schon zu Fuß gehst, dann schau dir doch mal Fetch API an
        Vorneweg, versteh ich das richtig, dass die Fetch API noch etwas moderner ist und quasi als Nachfolger für xmlhttp gedacht ist? Bist du hier etwas informierter, ob dass ein Pferd ist auf das man setzen sollte?

        Ansonsten meine Versuche das ganze damit zum laufen zu bekommen:

        ajaxWrapperPOST wird druch fetchApiWrapperPOST ersetzt und dein Snippet zum Body parsen ist mit eingefügt, der Rest ist unverändert (ajaxWrapperPOST hat nun einwandfrei funktioniert).
        Code:
        function fetchApiWrapperPOST(url, functionWhenReady, data) {
            fetch(url,
                {
                    method : 'post',
                    headers: {
                        'Accept': 'application/json',
                        'Cotent-Type': 'application/json'
                    },
                    body: JSON.stringify(data)
                }
            )
                .then(function (response) {
                    functionWhenReady(response)
                })
                .catch(function (error) {
                    console.error(error);
                });
        }
        Das liefert mir als Antwort:
        Code:
        Response { type: "basic", url: "http://localhost/index/create", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, bodyUsed: false }
        Aus dem Teil bodyUsed: false schließe ich, dass hier auch irgendwas schief gegangen sein muss, dann auch der "probieren geht über studieren"-Ansatz da via response.json() drauf zuzugreifen liefert nur ein 'state pending' zurück.
        https://developer.mozilla.org/en-US/...b/API/Response

        Hast du hier noch einen guten Tipp?

        Kommentar


        • #5
          Schau mal hier, das Thema hatten wir kürzlich: https://www.php.de/forum/webentwicklung/javascript-ajax-und-mehr/1502601-asyncron-er-ajax-request-in-funktion-zurückgeben?p=1502979#post1502979

          Kommentar


          • #6
            Hatte ich sogar schonmal gelesen, wenn auch weniger aufmerksam als jetzt nochmal
            Grundsätzlich zeigt mir das, dass ich die Fetch API aufgrund der Eigenenschaften von "Promises" sehr gern nutzen würde. Außerdem zeigt mir das, dass .then im Wrapper aufzurufen eher Quatsch ist und mir den Vorteil direkt wieder negiert. - danke.

            Das konkrete Problem, d.h. warum mein Response body leer ist komme ich damit aber nicht dichter, dass gepostet Beispiel von lottikarotti in dem Thread bezieht mein Problem leider nicht mit ein.

            Kommentar


            • #7
              Zitat von ChromOxid Beitrag anzeigen
              Das konkrete Problem, d.h. warum mein Response body leer ist komme ich damit aber nicht dichter, dass gepostet Beispiel von lottikarotti in dem Thread bezieht mein Problem leider nicht mit ein.
              Wie gesagt. Wenn du Deine Daten im application/json Format an den Server sendest, wird PHP das nicht automatisch verarbeiten. Dann musst du händisch an den Input-Stream ran und den Body parsen (siehe mein Code-Beispiel in #3).

              Edit
              Nachdem ich dein Post nochmal genauer gelesen habe, ist mir aufgefallen, dass du nun vom Response sprichst. Mir ist auch aufgefallen, dass dein "Content-Type"-Header einen Tippfehler hat. Ansonsten können wir jetzt nur die Frage stellen: was wird denn PHP-seitig ausgegeben? Und bachte das res.json() in meinem Beispiel zur fetch-API. Damit wird der Response-Body dekodiert.
              [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

              Kommentar


              • #8
                Wie gesagt. Wenn du Deine Daten im application/json Format an den Server sendest, wird PHP das nicht automatisch verarbeiten. Dann musst du händisch an den Input-Stream ran und den Body parsen (siehe mein Code-Beispiel in #3).
                Ist enthalten, der "gewöhnliche" Ajax request war dann auch erfolgreich und mit dem erwarteten Inhalt.
                dein Snippet zum Body parsen ist mit eingefügt
                PHP-Code:
                    public function createAction()
                    {
                        
                $this->view->disable();
                        
                $body file_get_contents('php://input');
                        
                $data json_decode($body);

                        return 
                json_encode($data);
                    } 
                Nachdem ich dein Post nochmal genauer gelesen habe, ist mir aufgefallen, dass du nun vom Response sprichst. Mir ist auch aufgefallen, dass dein "Content-Type"-Header einen Tippfehler hat. Ansonsten können wir jetzt nur die Frage stellen: was wird denn PHP-seitig ausgegeben? Und bachte das res.json() in meinem Beispiel zur fetch-API. Damit wird der Response-Body dekodiert.
                peinlich... ausgebessert.

                Php macht hier alles richtig, wenn ich mir den HTTP-Request anschaue bekomme ich (nach der Ausbesserung des Tippfehlers) als Antwort ein JSON mit den erwarteten Eigenschaften x und y.

                Das Ergebnis der Fetch API ist unverändert.

                Code:
                 
                 functionWhenReady(response.json())
                sorgt dafür, dass ich als Output in der Konsole folgendes bekomme: "Promise { <state>: "pending" }", was vermute ich damit zusammenhängt das bodyUsed in der Response auf "false" steht, allerdings scheitere ich daran, dadran was zu drehen.

                Kommentar


                • #9
                  Dann probiere stattdessen mal folgendes in der Konsole:
                  PHP-Code:
                  response.json().then(data => console.log(data)); 
                  Edit
                  Damit das mit den Promises vielleicht ein wenig verständlicher wird, habe ich das Beispiel mal ein wenig angepasst und kommentiert:

                  PHP-Code:
                  fetch('http://ip.jsontest.com/', {
                    
                  method'POST'
                  })

                    
                  // -> when fetch() resolves then ..
                    
                  .then((res) => {
                      if(!
                  res.ok){
                        throw 
                  Error(res.statusText);
                      }
                      return 
                  res.json(); // <- chain up next promise
                    
                  })

                    
                  // -> when res.json() resolves then ..
                    
                  .then((data) => {
                      
                  console.log(data.ip)
                    })

                    
                  // on error..
                    
                  .catch((err) => {
                      
                  console.error(err)
                    }); 
                  [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

                  Kommentar


                  • #10
                    Zitat von lottikarotti Beitrag anzeigen
                    Dann probiere stattdessen mal folgendes in der Konsole:
                    PHP-Code:
                    response.json().then(data => console.log(data)); 
                    Code:
                    Response { type: "basic", url: "http://localhost/index/create", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, bodyUsed: false }  ajaxWrapper.js:44:5
                    response.json().then(data => console.log(data));  
                    ReferenceError: response is not defined [Weitere Informationen]
                    Für mein Verständnis:
                    fetch(...).then() wird ausgeführt wenn auf die Anfrage ein Antwort kommt.
                    Die Antwort ist ein Response-Objekt, in dem einige Daten zur Antwort enthalten sind, z.B. status: 200, d.h. was HTTP anging lief hier alles super.
                    Im HTTP-Header wird als Inhalt der Antwort ein JSON Objekt angezeigt, d.h. auch der Inhalt der Antwort stimmt.

                    Mein Fehler kann folglich eigentlich nur in der fetch Methode stecken, vermutlich weil diese garnicht weiß, dass ich den Body der Antwort auch haben möchte.
                    Im Code eingegrenzt also hier:
                    Code:
                        fetch(url,
                            {
                                method: 'post',
                                headers: {
                                    'Accept': 'application/json',
                                    'Content-Type': 'application/json'
                                },
                                body: JSON.stringify(data)
                            }
                        )
                    Soweit richtig oder habe ich bis hier schon ein Verständnisproblem?

                    Kommentar


                    • #11
                      Zitat von ChromOxid Beitrag anzeigen
                      Für mein Verständnis:
                      fetch(...).then() wird ausgeführt wenn auf die Anfrage ein Antwort kommt.
                      Vereinfacht ausgedrückt liefert fetch(..) ein Promise-Objekt zurück, welches sich via then() bemerkbar macht, sobald die asynchrone Operation abgeschlossen ist. Das Ergebnis davon wird als Parameter an then() übergeben. In diesem Fall ist das ein Response-Objekt. Dieses Response-Objekt stellt eine .json()-Methode zur Verfügung, um den Response-Body zu dekodieren. Auch diese Methode liefert wieder ein Promise-Objekt zurück und übergibt das Ergebnis an then().

                      Im Prinzip wird also folgendes gemacht:

                      PHP-Code:
                      fetch(..)
                        .
                      then((response) => {
                          
                      response.json().then((data) => {
                            
                      console.log(data);
                          });
                        }); 
                      Da man so aber eine unschöne Verschachtelung erzeugt, gibt es die sog. Promise-Chains. Das obige Beispiel entspricht folgendem:

                      PHP-Code:
                      fetch(..)
                        .
                      then((response) => {
                          return 
                      response.json();
                        })
                        .
                      then((data) => {
                          
                      console.log(data);
                        }); 
                      ---

                      Hier nochmal ein Beispiel dafür (check out the fiddle):

                      PHP-Code:
                      let promise = new Promise(resolve => resolve(1));

                      promise
                        
                      .then((val) => {
                          
                      console.log(val);
                          return 
                      val 1;
                        })
                        .
                      then((val) => {
                          
                      console.log(val);
                          return 
                      val 1;
                        })
                        .
                      then((val) => {
                          
                      console.log(val);
                          return new 
                      Promise((resolve) => {
                            
                      setTimeout(() => resolve(val 1), 2000);
                          });
                        })
                        .
                      then((val) => {
                          
                      console.log(val);
                          return 
                      val 1;
                        })
                        .
                      then((val) => {
                          throw new 
                      Error('whoops, something went wrong');
                        })
                        .
                      then((val) => {
                          
                      // -> this callback will be skipped
                          
                      console.log(val);
                        })
                        .catch((
                      err) => {
                          
                      console.log(err);
                        }); 
                      Ich hoffe das hilft dir weiter.
                      [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

                      Kommentar

                      Lädt...
                      X