W jaki sposób mogę POST zakodować dane formularza za pomocą $ http bez jQuery?

195

Jestem nowy w AngularJS i na początek pomyślałem o opracowaniu nowej aplikacji przy użyciu tylko AngularJS.

Próbuję nawiązać połączenie AJAX po stronie serwera, używając $httpaplikacji Angular.

Aby wysłać parametry, próbowałem:

$http({
    method: "post",
    url: URL,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: $.param({username: $scope.userName, password: $scope.password})
}).success(function(result){
    console.log(result);
});

Działa, ale używa także jQuery w $.param. Aby usunąć zależność od jQuery, próbowałem:

data: {username: $scope.userName, password: $scope.password}

ale to wydawało się zawodzić. Potem spróbowałem params:

params: {username: $scope.userName, password: $scope.password}

ale to również wydawało się nieskuteczne. Potem spróbowałem JSON.stringify:

data: JSON.stringify({username: $scope.userName, password: $scope.password})

Znalazłem te możliwe odpowiedzi na moje poszukiwanie, ale nie powiodło się. czy robię coś źle? Jestem pewien, że AngularJS zapewniłby tę funkcjonalność, ale jak?

Veer Shrivastav
źródło
Nie wiem, jaki jest rzeczywisty problem, ale czy próbowałeś tego$http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});
Mritunjay,
1
Twoja pierwsza metoda powinna działać, jest $scope.userNamezdefiniowana? dlaczego nie spróbować data: data?
Kevin B
@KevinB: przepraszam .. Dokonałem poprawnej edycji.
Veer Shrivastav
@mritunjay: przepraszam .. Dokonałem edycji .. Próbowałem tego samego.
Veer Shrivastav
@Veer działało, czy nadal masz problemy?
V31

Odpowiedzi:

409

Myślę, że musisz zrobić, to przekształcić dane z obiektu nie w ciąg JSON, ale w parametry adresu URL.

Z bloga Bena Nadela .

Domyślnie usługa $ http przekształci wychodzące żądanie, serializując dane jako JSON, a następnie publikując je z typem treści „application / json”. Gdy chcemy opublikować wartość jako FORMULARZ, musimy zmienić algorytm serializacji i opublikować dane z typem zawartości „application / x-www-form-urlencoded”.

Przykład stąd .

$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: {username: $scope.userName, password: $scope.password}
}).then(function () {});

AKTUALIZACJA

Aby skorzystać z nowych usług dodanych do AngularJS 1.4, patrz

allenhwkim
źródło
41
Dziękujemy za nieużywanie JQuery!
OverMars,
1
co jeśli muszę przesłać dane wieloczęściowe / formularze?
Dejell
2
Tak długo, jak kątowe osadza jqLite pod angular.element, możesz po prostureturn angular.element.param(obj);
Vicary
4
@Vicary Należy pamiętać, że param () nie jest zaimplementowany w jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.element
Alex Pavlov
1
to jest inna droga var obj = {a: 1, b: 2}; Object.keys(obj).reduce(function(p, c) { return p.concat([encodeURIComponent(c) + "=" + encodeURIComponent(obj[c])]); }, []).join('&');
test30
137

Zmienne kodujące adresy URL korzystające tylko z usług AngularJS

W AngularJS 1.4 i nowszych dwie usługi mogą obsługiwać proces kodowania danych dla żądań POST, eliminując potrzebę manipulowania danymi za transformRequestpomocą zewnętrznych zależności lub takich jak jQuery:

  1. $httpParamSerializerJQLike- serializator inspirowany przez jQuery's .param()( zalecane )

  2. $httpParamSerializer - serializator używany przez sam Angular do żądań GET

Przykładowe użycie

$http({
  url: 'some/api/endpoint',
  method: 'POST',
  data: $httpParamSerializerJQLike($scope.appForm.data), // Make sure to inject the service you choose to the controller
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
  }
}).then(function(response) { /* do something here */ });

Zobacz bardziej szczegółowe demo Plunkera


Jakie są $httpParamSerializerJQLikei $httpParamSerializerróżne

Ogólnie wydaje się, że $httpParamSerializerużywa mniej „tradycyjnego” formatu kodowania adresów URL niż w $httpParamSerializerJQLikeprzypadku złożonych struktur danych.

Na przykład (ignorowanie procentowego kodowania nawiasów):

Kodowanie tablicy

{sites:['google', 'Facebook']} // Object with array property

sites[]=google&sites[]=facebook // Result with $httpParamSerializerJQLike

sites=google&sites=facebook // Result with $httpParamSerializer

Kodowanie obiektu

{address: {city: 'LA', country: 'USA'}} // Object with object property

address[city]=LA&address[country]=USA // Result with $httpParamSerializerJQLike

address={"city": "LA", country: "USA"} // Result with $httpParamSerializer
Boaz
źródło
Jak możemy to wykorzystać w zasobach $ w fabryce?
stilllife
2
Powinien być $http.({...zamiast`$http.post({...
Carlos Granados,
@CarlosGranados Dzięki za zauważenie. Poprawiłem tę literówkę tutaj oraz w demie Plunkera.
Boaz,
Działa
4
Oto odpowiedź, której szukałem w AngularJS. Chciałbym, żeby plakat wybrał to jako najlepszą odpowiedź.
Marty Chang
61

Wszystko to wygląda na przesadne (lub nie działa) ... po prostu zrób to:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Serj Sagan
źródło
11
Nareszcie zdrowy rozsądek
Jlewkovich
Czy to nie wyśle ​​żądania z niewłaściwym nagłówkiem typu treści?
Phil
To działało dla mnie ... nie jestem pewien, jaki był nagłówek, ale żądanie zadziałało i pozwoliło na pomyślne uwierzytelnienie. Może przetestujesz to i poinformujesz nas o tym.
Serj Sagan,
5
@Phil Wydaje mi się, że może to zależeć od serwera, otrzymałem złe żądanie, dopóki nie dodałem {headers: {'Content-Type': 'application / x-www-form-urlencoded'}} jako argumentu konfiguracyjnego lub użyj źródła pokazuje konstruktor $ http (config) podobny do odpowiedzi moices. W każdym razie jest to lepsze niż zaakceptowana odpowiedź, ponieważ nie wprowadza jakiejś magicznej transformacji i nie wymaga użytkownika jakiejś usługi pomocniczej. Dzięki!
Mr. Bungle
23

Problemem jest format ciągu JSON. Możesz użyć prostego ciągu URL w danych:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
moices
źródło
7
musisz użyć, encodeURIComponent($scope.userName)aby zakodować dane w "&myCustomParam=1"
adresie
2
to jedyna odpowiedź, która zadziałała dla mnie!
Pominąłem
4

Oto, jak powinno być (i proszę, nie wprowadzaj żadnych zmian w backendach ... na pewno nie ... jeśli twój front stack nie obsługuje application/x-www-form-urlencoded, to wyrzuć go ... mam nadzieję, że AngularJS to robi!

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: 'username='+$scope.username+'&password='+$scope.password
 }).then(function(response) {
    // on success
 }, function(response) {
    // on error
 });

Działa jak urok z AngularJS 1.5

Ludzie, dajmy wam radę:

  • używaj obietnic w .then(success, error)kontaktach $http, zapominaj .sucessi .erroroddzwoń (ponieważ są przestarzałe)

  • Ze strony angularjs tutajNie można już używać ciągu JSON_CALLBACK jako symbolu zastępczego do określania, gdzie powinna się znaleźć wartość parametru wywołania zwrotnego ”.

Jeśli Twój model danych jest bardziej złożony niż sama nazwa użytkownika i hasło, nadal możesz to zrobić (jak sugerowano powyżej)

$http({
     method: 'POST',
     url: 'api_endpoint',
     headers: {'Content-Type': 'application/x-www-form-urlencoded'},
     data: json_formatted_data,
     transformRequest: function(data, headers) {
          return transform_json_to_urlcoded(data); // iterate over fields and chain key=value separated with &, using encodeURIComponent javascript function
     }
}).then(function(response) {
  // on succes
}, function(response) {
  // on error
});

Dokument do encodeURIComponentmożna znaleźć tutaj

Mahieddine M. Ichir
źródło
3

Jeśli jest to formularz, spróbuj zmienić nagłówek na:

headers[ "Content-type" ] = "application/x-www-form-urlencoded; charset=utf-8";

a jeśli nie jest to formularz i zwykły plik Json, wypróbuj następujący nagłówek:

headers[ "Content-type" ] = "application/json";
V31
źródło
Nic nie otrzymuję. Nadal otrzymałem pustą $_POSTtablicę.!
Veer Shrivastav
czy to połączenie $ http w twoim kontrolerze?
V31,
jeszcze jedno to php twojego serwera?
V31,
Znalazłem rozwiązanie tego samego. Czy nadal masz problem @ Veer?
V31,
2
$http({

    method: "POST",
    url: "/server.php",
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    data: "name='Олег'&age='28'",


}).success(function(data, status) {
    console.log(data);
    console.log(status);
});
użytkownik8483090
źródło
4
Tylko odpowiedzi na kod nie są przydatne dla społeczności. Proszę spojrzeć na Jak odpowiedzieć
abpatil
1

Z dokumentów $ http powinno to działać ..

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Srinath
źródło
@Kevin nie jestem tego pewien, ale ... kiedy próbowałem wysłać ciąg, pokazał mi błąd
Srinath
@KevinB W porządku .. Rozumiem ... myślę, że nagłówki należy zmienić podczas wysyłania ciągu .. stackoverflow.com/a/20276775/2466168
Srinath
1
Pamiętaj, że przesłanie poprawnego headersnie wpłynie na to, dataktóre nadal będą musiały zostać zakodowane w taki czy inny sposób.
Boaz
dane są nadal przesyłane w formacie json, musisz zakodować dane w x-www-form-urlencoded samo dodanie nagłówka to za mało
wendellmva
1

musisz wysłać zwykły obiekt javascript, nic więcej

           var request = $http({
                method: "post",
                url: "process.cfm",
                transformRequest: transformRequestAsFormPost,
                data: { id: 4, name: "Kim" }
            });

            request.success(
                function( data ) {
                    $scope.localData = data;
                }
            );

jeśli masz php jako back-end, będziesz musiał dokonać dalszych modyfikacji .. sprawdź ten link, aby naprawić stronę serwera php

harishr
źródło
to dokładnie NIE jest to, o co prosił, konkretnie zapytał, w jaki sposób można je uzyskać jako x-www-form-urlencodod, ponieważ ma problemy z opublikowanymi materiałami json.
ppetermann
@ppetermann, czy sprawdziłeś historię edycji pytania przed oddaniem głosu ...
harishr
1

Chociaż późna odpowiedź, znalazłem kątowe UrlSearchParams działało dla mnie bardzo dobrze, zajmuje się również kodowaniem parametrów.

let params = new URLSearchParams();
params.set("abc", "def");

let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded'});
let options = new RequestOptions({ headers: headers, withCredentials: true });
this.http
.post(UrlUtil.getOptionSubmitUrl(parentSubcatId), params, options)
.catch();
vanval
źródło
0

To zadziałało dla mnie. Używam angular dla frontonu i laravel php dla back-endu. W moim projekcie sieć kątowa wysyła dane JSON do zaplecza laravel.

To jest mój kontroler kątowy.

var angularJsApp= angular.module('angularJsApp',[]);
angularJsApp.controller('MainCtrl', function ($scope ,$http) {

    $scope.userName ="Victoria";
    $scope.password ="password"


       $http({
            method :'POST',
            url:'http://api.mywebsite.com.localhost/httpTest?callback=JSON_CALLBACK',
            data: { username :  $scope.userName , password: $scope.password},
            headers: {'Content-Type': 'application/json'}
        }).success(function (data, status, headers, config) {
            console.log('status',status);
            console.log('data',status);
            console.log('headers',status);
        });

});

To jest mój kontroler laravel php.

public function httpTest(){
        if (Input::has('username')) {
            $user =Input::all();
            return  Response::json($user)->setCallback(Input::get('callback'));
        }
    }

To jest mój routing Laravela

Route::post('httpTest','HttpTestController@httpTest');

Wynik w przeglądarce to

status 200
danych JSON_CALLBACK ({„nazwa użytkownika”: „Victoria”, „hasło”: „hasło”, „oddzwanianie”: „JSON_CALLBACK”}); httpTesting.js: 18 funkcja nagłówków (c) {a || (a = sc (b)); zwraca c? a [K (c)] || null: a}

Istnieje chromowane rozszerzenie o nazwie listonosz. Możesz użyć do przetestowania adresu URL zaplecza, czy działa. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

mam nadzieję, że moja odpowiedź ci pomoże.

meazuri
źródło