it-swarm.com.de

Wie kann ich Daten als Formulardaten anstelle einer Anforderungsnutzlast veröffentlichen?

Im folgenden Code ruft die AngularJS $http -Methode die URL auf und sendet das xsrf-Objekt als "Request Payload" (wie auf der Registerkarte Chrome Debugger-Netzwerk beschrieben). Die Methode jQuery $.ajax führt denselben Aufruf aus, sendet jedoch xsrf als "Formulardaten".

Wie kann ich AngularJS veranlassen, XSRF als Formulardaten anstelle einer Anforderungsnutzlast zu übermitteln?

var url = 'http://somewhere.com/';
var xsrf = {fkey: 'xsrf key'};

$http({
    method: 'POST',
    url: url,
    data: xsrf
}).success(function () {});

$.ajax({
    type: 'POST',
    url: url,
    data: xsrf,
    dataType: 'json',
    success: function() {}
});
513
mjibson

Die folgende Zeile muss dem übergebenen $ http-Objekt hinzugefügt werden:

headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}

Und die übergebenen Daten sollten in eine URL-codierte Zeichenfolge konvertiert werden:

> $.param({fkey: "key"})
'fkey=key'

Sie haben also etwas wie:

$http({
    method: 'POST',
    url: url,
    data: $.param({fkey: "key"}),
    headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})

Von: https://groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ

AKTUALISIEREN

Informationen zur Verwendung neuer Dienste, die mit AngularJS V1.4 hinzugefügt wurden, finden Sie unter

604
mjibson

Wenn Sie jQuery nicht in der Lösung verwenden möchten, können Sie dies versuchen. Die Lösung wurde von hier aus gefunden https://stackoverflow.com/a/1714899/1784301

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    transformRequest: function(obj) {
        var str = [];
        for(var p in obj)
        str.Push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        return str.join("&");
    },
    data: xsrf
}).success(function () {});
192
Anthony

Die anhaltende Verwirrung um dieses Problem hat mich dazu inspiriert, einen Blog-Beitrag darüber zu schreiben. Die in diesem Beitrag vorgeschlagene Lösung ist besser als Ihre derzeitige bestbewertete Lösung, da Sie nicht darauf beschränkt sind, Ihr Datenobjekt für $ http-Serviceaufrufe zu parametrisieren. Mit meiner Lösung können Sie einfach weiterhin tatsächliche Datenobjekte an $ http.post () usw. übergeben und dennoch das gewünschte Ergebnis erzielen.

Die bestbewertete Antwort basiert außerdem auf der Aufnahme von vollständigem jQuery in die Seite für die $ .param () -Funktion, während meine Lösung jQuery-unabhängig und bereit für AngularJS ist.

http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

Hoffe das hilft.

91
Ezekiel Victor

Ich habe ein paar der anderen Antworten genommen und etwas sauberer gemacht. Setzen Sie diesen .config() -Aufruf an das Ende Ihres angle.module in Ihrer app.js:

.config(['$httpProvider', function ($httpProvider) {
  // Intercept POST requests, convert to standard form encoding
  $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
  $httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
    var key, result = [];

    if (typeof data === "string")
      return data;

    for (key in data) {
      if (data.hasOwnProperty(key))
        result.Push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
    }
    return result.join("&");
  });
}]);
82
kzar

Ab AngularJS v1.4.0 gibt es einen integrierten $httpParamSerializer -Dienst, der jedes Objekt in einen Teil einer HTTP-Anforderung gemäß den Regeln konvertiert, die auf der Seite docs aufgeführt sind.

Es kann so verwendet werden:

$http.post('http://example.com', $httpParamSerializer(formDataObj)).
    success(function(data){/* response status 200-299 */}).
    error(function(data){/* response status 400-999 */});

Denken Sie daran, dass für einen korrekten Formularbeitrag der Header Content-Type geändert werden muss. Um dies global für alle POST Anfragen zu tun, kann dieser Code (entnommen aus Albireos Halbantwort) verwendet werden:

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

Um dies nur für den aktuellen Beitrag zu tun, muss die Eigenschaft headers des Anfrageobjekts geändert werden:

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'application/x-www-form-urlencoded'
 },
 data: $httpParamSerializer(formDataObj)
};

$http(req);
57
Mitja

Sie können das Verhalten global definieren:

$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

Sie müssen es also nicht jedes Mal neu definieren:

$http.post("/handle/post", {
    foo: "FOO",
    bar: "BAR"
}).success(function (data, status, headers, config) {
    // TODO
}).error(function (data, status, headers, config) {
    // TODO
});
24
Albireo

Als Problemumgehung können Sie den Code, der den POST empfängt, einfach auf Anwendungs-/JSON-Daten reagieren lassen. Für PHP habe ich den folgenden Code hinzugefügt, sodass ich POST entweder in formularkodierter Form oder in JSON verwenden kann.

//handles JSON posted arguments and stuffs them into $_POST
//angular's $http makes JSON posts (not normal "form encoded")
$content_type_args = explode(';', $_SERVER['CONTENT_TYPE']); //parse content_type string
if ($content_type_args[0] == 'application/json')
  $_POST = json_decode(file_get_contents('php://input'),true);

//now continue to reference $_POST vars as usual
20
James Bell

Diese Antworten sehen aus wie verrückter Overkill, manchmal ist einfach einfach besser:

$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
                     "&password=" + encodeURIComponent(password) +
                     "&grant_type=password"
).success(function (data) {
//...
16
Serj Sagan

Sie können es mit der folgenden Lösung versuchen

$http({
        method: 'POST',
        url: url-post,
        data: data-post-object-json,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        transformRequest: function(obj) {
            var str = [];
            for (var key in obj) {
                if (obj[key] instanceof Array) {
                    for(var idx in obj[key]){
                        var subObj = obj[key][idx];
                        for(var subKey in subObj){
                            str.Push(encodeURIComponent(key) + "[" + idx + "][" + encodeURIComponent(subKey) + "]=" + encodeURIComponent(subObj[subKey]));
                        }
                    }
                }
                else {
                    str.Push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
                }
            }
            return str.join("&");
        }
    }).success(function(response) {
          /* Do something */
        });
9
tmquang6805

Erstellen Sie einen Adapterservice für Post:

services.service('Http', function ($http) {

    var self = this

    this.post = function (url, data) {
        return $http({
            method: 'POST',
            url: url,
            data: $.param(data),
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
    }

}) 

Verwenden Sie es in Ihren Controllern oder was auch immer:

ctrls.controller('PersonCtrl', function (Http /* our service */) {
    var self = this
    self.user = {name: "Ozgur", eMail: null}

    self.register = function () {
        Http.post('/user/register', self.user).then(function (r) {
            //response
            console.log(r)
        })
    }

})
8
Ozgur

Es gibt ein wirklich nettes Tutorial, das sich mit diesem und anderen verwandten Dingen befasst - Einreichen von AJAX Forms: The AngularJS Way .

Grundsätzlich müssen Sie den Header der POST -Anforderung festlegen, um anzugeben, dass Sie Formulardaten als URL-codierte Zeichenfolge senden, und die zu sendenden Daten auf dasselbe Format festlegen

$http({
  method  : 'POST',
  url     : 'url',
  data    : $.param(xsrf),  // pass in data as strings
  headers : { 'Content-Type': 'application/x-www-form-urlencoded' }  // set the headers so angular passing info as form data (not request payload)
});

Beachten Sie, dass die Hilfefunktion param () von jQuery hier zum Serialisieren der Daten in einen String verwendet wird. Sie können dies jedoch auch manuell tun, wenn Sie jQuery nicht verwenden.

7
robinmitra
var fd = new FormData();
    fd.append('file', file);
    $http.post(uploadUrl, fd, {
        transformRequest: angular.identity,
        headers: {'Content-Type': undefined}
    })
    .success(function(){
    })
    .error(function(){
    });

Bitte checken sie aus! https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

7
aul

Für Symfony2-Benutzer:

Wenn Sie nichts in Ihrem Javascript ändern möchten, damit dies funktioniert, können Sie diese Änderungen in Ihrer symfony-App vornehmen:

Erstellen Sie eine Klasse, die die Symfony\Component\HttpFoundation\Request-Klasse erweitert:

<?php

namespace Acme\Test\MyRequest;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;

class MyRequest extends Request{


/**
* Override and extend the createFromGlobals function.
* 
* 
*
* @return Request A new request
*
* @api
*/
public static function createFromGlobals()
{
  // Get what we would get from the parent
  $request = parent::createFromGlobals();

  // Add the handling for 'application/json' content type.
  if(0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/json')){

    // The json is in the content
    $cont = $request->getContent();

    $json = json_decode($cont);

    // ParameterBag must be an Array.
    if(is_object($json)) {
      $json = (array) $json;
  }
  $request->request = new ParameterBag($json);

}

return $request;

}

}

Verwenden Sie jetzt Ihre Klasse in der Datei app_dev.php (oder einer anderen von Ihnen verwendeten Indexdatei).

// web/app_dev.php

$kernel = new AppKernel('dev', true);
// $kernel->loadClassCache();
$request = ForumBundleRequest::createFromGlobals();

// use your class instead
// $request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
4
carmel

Ich verwende derzeit die folgende Lösung, die ich gefunden in der AngularJS-Google-Gruppe.

 $ http 
. post ('/ echo/json /', 'json =' + encodeURIComponent (angle.toJson (data)), {
 header: {
 'Content-Type': 'application/x-www-form-urlencoded; Zeichensatz = UTF-8' 
} 
}). Erfolg (Funktion (Daten) {
 $ scope.data = data; 
}); 

Beachten Sie, dass Sie, wenn Sie PHP verwenden, Request::createFromGlobals() einer Symfony 2-HTTP-Komponente verwenden müssen, um dies zu lesen, da $ _POST damit nicht automatisch geladen wird.

3
Aditya M P

Einfach festlegen, dass der Inhaltstyp nicht ausreicht. Die Formulardaten müssen vor dem Senden mit einer URL verschlüsselt werden. $http.post(url, jQuery.param(data))

3
Merlin Ran

Vollständige Antwort (seit angular 1.4). Sie müssen die Abhängigkeit $ httpParamSerializer einschließen

var res = $resource(serverUrl + 'Token', { }, {
                save: { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
            });

            res.save({ }, $httpParamSerializer({ param1: 'sdsd', param2: 'sdsd' }), function (response) {

            }, function (error) { 

            });
2

AngularJS macht es richtig, da es den folgenden Inhaltstyp im http-Request-Header ausführt:

Content-Type: application/json

Wenn Sie mit PHP wie mir oder sogar mit Symfony2 arbeiten, können Sie einfach Ihre Serverkompatibilität für den json-Standard wie hier beschrieben erweitern: http://silex.sensiolabs.org/doc/cookbook/json_request_body.html

Die Symfony2-Methode (z. B. in Ihrem DefaultController):

$request = $this->getRequest();
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
    $data = json_decode($request->getContent(), true);
    $request->request->replace(is_array($data) ? $data : array());
}
var_dump($request->request->all());

Der Vorteil wäre, dass Sie keinen jQuery-Parameter benötigen und AngularJS als native Methode für solche Anfragen verwenden können.

2
Michael

In Ihrer App-Konfiguration -

$httpProvider.defaults.transformRequest = function (data) {
        if (data === undefined)
            return data;
        var clonedData = $.extend(true, {}, data);
        for (var property in clonedData)
            if (property.substr(0, 1) == '$')
                delete clonedData[property];

        return $.param(clonedData);
    };

Mit Ihrer Ressourcenanfrage -

 headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
1
Vivek

Dies ist keine direkte Antwort, sondern eine etwas andere Designrichtung:

Veröffentlichen Sie die Daten nicht als Formular, sondern als JSON-Objekt, das direkt dem serverseitigen Objekt zugeordnet werden soll, oder verwenden Sie die Pfadvariable REST .

Jetzt weiß ich, dass in Ihrem Fall keine der beiden Optionen geeignet ist, da Sie versuchen, einen XSRF-Schlüssel zu übergeben. Das Abbilden in eine Pfadvariable wie diese ist ein schreckliches Design:

http://www.someexample.com/xsrf/{xsrfKey}

Weil Sie von Natur aus den XSRF-Schlüssel auch an andere Pfade, /login, /book-appointment usw. übergeben möchten und Ihre hübsche URL nicht durcheinander bringen möchten

Interessanterweise ist es auch nicht angebracht, es als Objektfeld hinzuzufügen, da Sie jetzt auf jedem json-Objekt, das Sie an den Server übergeben, das Feld hinzufügen müssen

{
  appointmentId : 23,
  name : 'Joe Citizen',
  xsrf : '...'
}

Sie möchten auf keinen Fall ein weiteres Feld in Ihrer serverseitigen Klasse hinzufügen, das keine direkte semantische Zuordnung zum Domänenobjekt hat.

Meiner Meinung nach ist die beste Möglichkeit, Ihren xsrf-Schlüssel zu übergeben, ein HTTP-Header. Dies wird von vielen serverseitigen XSRF-Schutz-Webframeworkbibliotheken unterstützt. Zum Beispiel in Java Spring können Sie es mit dem Header X-CSRF-TOKEN übergeben .

Angulars hervorragende Fähigkeit, JS-Objekte an UI-Objekte zu binden, bedeutet, dass wir die Praxis, Formulare zu veröffentlichen, aufheben und stattdessen JSON veröffentlichen können. JSON kann einfach in ein serverseitiges Objekt de-serialisiert werden und unterstützt komplexe Datenstrukturen wie Karten, Arrays, verschachtelte Objekte usw.

Wie postet man ein Array in einer Formularnutzlast? Vielleicht so:

shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday

oder dieses:

shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday

Beide sind schlechtes Design ..

0
gerrytan

Dies ist, was ich für meinen Bedarf tue, wo ich die Anmeldedaten als Formulardaten an die API senden muss und das Javascript-Objekt (userData) automatisch in URL-codierte Daten konvertiert wird

        var deferred = $q.defer();
        $http({
            method: 'POST',
            url: apiserver + '/authenticate',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            transformRequest: function (obj) {
                var str = [];
                for (var p in obj)
                    str.Push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                return str.join("&");
            },
            data: userData
        }).success(function (response) {
            //logics
            deferred.resolve(response);
        }).error(function (err, status) {
           deferred.reject(err);
        });

So sind meine Userdaten

var userData = {
                grant_type: 'password',
                username: loginData.userName,
                password: loginData.password
            }
0
Shubham