AngularJS - Adakah cara untuk $ http.post mengirim parameter permintaan alih-alih JSON?

116

Saya memiliki beberapa kode lama yang membuat permintaan AJAX POST melalui metode posting jQuery dan terlihat seperti ini:

$.post("/foo/bar", requestData,
    function(responseData)
    {
        //do stuff with response
    }

requestData hanyalah sebuah objek javascript dengan beberapa properti string dasar.

Saya sedang dalam proses memindahkan barang-barang kami untuk menggunakan Angular, dan saya ingin mengganti panggilan ini dengan $ http.post. Saya datang dengan yang berikut:

$http.post("/foo/bar", requestData).success(
    function(responseData) {
        //do stuff with response
    }
});

Ketika saya melakukan ini, saya mendapat respon kesalahan 500 dari server. Menggunakan Firebug, saya menemukan bahwa ini mengirim tubuh permintaan seperti ini:

{"param1":"value1","param2":"value2","param3":"value3"}

JQuery yang berhasil $.postmengirim isi seperti ini:

param1=value1&param2=value2&param3=value3

Titik akhir yang saya tekan mengharapkan parameter permintaan, bukan JSON. Jadi, pertanyaan saya adalah adakah yang harus memberitahu $http.postuntuk mengirim objek javascript sebagai parameter permintaan daripada JSON? Ya, saya tahu saya bisa membuat string sendiri dari objek, tetapi saya ingin tahu apakah Angular menyediakan sesuatu untuk ini di luar kotak.

dnc253
sumber

Jawaban:

140

Saya pikir paramsparameter konfigurasi tidak akan berfungsi di sini karena menambahkan string ke url alih-alih tubuh tetapi untuk menambahkan apa yang disarankan Infeligo di sini adalah contoh penimpaan global dari transformasi default (menggunakan jQuery param sebagai contoh untuk mengonversi data ke string param).

Siapkan fungsi global transformRequest:

var app = angular.module('myApp');

app.config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});

Dengan cara itu semua panggilan ke $ http.post akan secara otomatis mengubah body ke format param yang sama yang digunakan oleh $.postpanggilan jQuery .

Perhatikan, Anda mungkin juga ingin menyetel header Jenis Konten per panggilan atau secara global seperti ini:

$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

Contoh transformRequest non-global per panggilan:

    var transform = function(data){
        return $.param(data);
    }

    $http.post("/foo/bar", requestData, {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        transformRequest: transform
    }).success(function(responseData) {
        //do stuff with response
    });
Gloopy
sumber
Saya bertanya-tanya apakah ada sesuatu selain memiliki fungsi transformRequest, tetapi sepertinya tidak ada. Terima kasih atas perhatiannya tentang fungsi param jQuery.
dnc253
Metode non-global per panggilan berfungsi dengan baik untuk saya, tetapi ketika mencoba mengatur secara global melalui $httpProvider.defaults, maka itu tidak berfungsi, ada petunjuk tentang ini?
Dfr
1
WRT mengkonfigurasinya secara global, saya juga mengalami masalah. Ketika saya mencoba melakukannya menggunakan potongan yang diberikan di sini, saya mendapatkan pesan kesalahan Cannot read property "jquery" of undefined.Bagaimana cara memperbaikinya? PS. Transformasi per panggilan berfungsi.
kshep92
@ kshep92 Apa yang terjadi adalah bahwa fungsi transformRequest dipanggil pada permintaan tanpa data sehingga 'data' tidak terdefinisi. Saya menambahkan penjaga sebelum 'return $ .param (data);'. Masukkan ini sebagai baris pertama ke fungsi transformRequest: 'if (data === undefined) return data;' Lihat hasil edit yang saya buat untuk jawabannya.
Jere.Jones
1
mulai Angular 1.4 Anda dapat menggunakan $ httpParamSerializer alih-alih jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
theRemix
21

Jika menggunakan Angular> = 1.4 , inilah solusi terbersih yang saya temukan yang tidak bergantung pada kustom atau eksternal apa pun:

angular.module('yourModule')
  .config(function ($httpProvider, $httpParamSerializerJQLikeProvider){
    $httpProvider.defaults.transformRequest.unshift($httpParamSerializerJQLikeProvider.$get());
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
});

Kemudian Anda dapat melakukannya di mana saja di aplikasi Anda:

$http({
  method: 'POST',
  url: '/requesturl',
  data: {
    param1: 'value1',
    param2: 'value2'
  }
});

Dan itu akan dengan benar membuat serial data sebagai param1=value1&param2=value2dan mengirimkannya ke /requesturldengan application/x-www-form-urlencoded; charset=utf-8header Jenis Konten seperti yang biasanya diharapkan dengan permintaan POST pada titik akhir.

Saeb Amini
sumber
17

Dari dokumentasi AngularJS:

params - {Object.} - Peta string atau objek yang akan diubah menjadi? key1 = value1 & key2 = value2 setelah url. Jika nilainya bukan string , itu akan menjadi JSONified.

Jadi, berikan string sebagai parameter. Jika Anda tidak menginginkannya, gunakan transformasi. Sekali lagi, dari dokumentasi:

Untuk mengganti transformasi ini secara lokal, tentukan fungsi transformasi sebagai properti transformRequest dan / atau transformResponse dari objek config. Untuk mengganti secara global transformasi default, timpa properti $ httpProvider.defaults.transformRequest dan $ httpProvider.defaults.transformResponse dari $ httpProvider.

Lihat dokumentasi untuk lebih jelasnya.

Infeligo
sumber
Saya melihat params dalam dokumentasi, dan seperti yang disebutkan Gloopy, saya membutuhkannya di bagian isi, dan bukan di URL. Saya bertanya-tanya apakah ada beberapa opsi atau sesuatu yang saya lewatkan untuk melakukan parameter, bukan JSON, tetapi sepertinya saya hanya perlu menggunakan properti transformRequest.
dnc253
15

Gunakan $.paramfungsi jQuery untuk membuat serial data JSON di requestData.

Singkatnya, menggunakan kode serupa seperti milik Anda:

$http.post("/foo/bar",
$.param(requestData),
{
    headers:
    {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    }
}
).success(
    function(responseData) {
        //do stuff with response
    }
});

Untuk menggunakan ini, Anda harus menyertakan jQuery di halaman Anda bersama dengan AngularJS.

Sagar Bhosale
sumber
7

Perhatikan bahwa pada Angular 1.4, Anda dapat membuat data formulir tanpa menggunakan jQuery.

Di app.js:

module.run(function($http, $httpParamSerializerJQLike) {
  $http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});

Kemudian di pengontrol Anda:

$http({
    method: 'POST',
    url: myUrl',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: myData
});
Thomas Graziani
sumber
Jawaban ini bagus. Ini membahas 2 masalah utama dengan Post from Angular. Header harus diatur dengan benar dan Anda harus membuat serial data json. Jika Anda tidak membutuhkan dukungan IE8, gunakan 1.4+ atau yang lebih baru.
mbokil
Saya baru saja menerapkan ini dan ini menyelesaikan masalah yang saya alami dengan posting, tetapi ini juga mengubah cara kerja tambalan dan tampaknya telah merusak semua penggunaan $ http.patch () saya.
Mike Feltman
5

Ini mungkin sedikit peretasan, tetapi saya menghindari masalah dan mengubah json menjadi array POST PHP di sisi server:

$_POST = json_decode(file_get_contents('php://input'), true);
TimoSolo
sumber
Saya telah menggunakan metode ini, tetapi saya membencinya; dan butuh waktu lama bagi saya untuk mencari tahu mengapa saya harus menggunakan ini.
meconroy
seperti yang saya katakan - rasanya hacky. Seperti kebanyakan php;)
TimoSolo
5

Saya juga memiliki masalah dengan pengaturan otentikasi http khusus karena $ resource cache permintaan.

Untuk membuatnya berfungsi, Anda harus menimpa header yang ada dengan melakukan ini

var transformRequest = function(data, headersGetter){
  var headers = headersGetter();
  headers['Authorization'] = 'WSSE profile="UsernameToken"';
  headers['X-WSSE'] = 'UsernameToken ' + nonce
  headers['Content-Type'] = 'application/json';
};

return $resource(
  url,
    {
    },
    {
      query: {
        method: 'POST',
        url: apiURL + '/profile',
        transformRequest: transformRequest,
        params: {userId: '@userId'}
      },
    }
);

Saya harap saya bisa membantu seseorang. Aku butuh 3 hari untuk memikirkan yang satu ini.

Frank Marcelo
sumber
Saya kira Anda baru saja menyelamatkan saya 3 hari kerja. Terima kasih!!! Saya masih mencoba mencari tahu apakah saya dapat mencegat panggilan permintaan entah bagaimana sehingga saya dapat menyuntikkan header khusus untuk setiap panggilan.
marcoseu
4

Ubah header default:

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

Kemudian gunakan $.parammetode JQuery :

var payload = $.param({key: value});
$http.post(targetURL, payload);
Zags
sumber
3
   .controller('pieChartController', ['$scope', '$http', '$httpParamSerializerJQLike', function($scope, $http, $httpParamSerializerJQLike) {
        var data = {
                TimeStamp : "2016-04-25 12:50:00"
        };
        $http({
            method: 'POST',
            url: 'serverutilizationreport',
            headers: {'Content-Type': 'application/x-www-form-urlencoded'},
            data: $httpParamSerializerJQLike(data),
        }).success(function () {});
    }
  ]);
Rohit Luthra
sumber
Menurut saya yang paling sederhana dan termudah ... Mungkin ada banyak cara lain
Rohit Luthra
2

Penyesuaian cepat - bagi Anda yang mengalami masalah dengan konfigurasi global fungsi transformRequest, berikut cuplikan yang saya gunakan untuk menghilangkan Cannot read property 'jquery' of undefinedkesalahan:

$httpProvider.defaults.transformRequest = function(data) {
        return data != undefined ? $.param(data) : null;
    }
kshep92
sumber
0

Saya sering kali menemukan perilaku bermasalah dari keseluruhan ini. Saya menggunakannya dari express (tanpa pengetikan) dan bodyParser (dengan pengetikan dt ~ body-parser).

Saya tidak mencoba mengunggah file, melainkan hanya untuk menafsirkan JSON yang diberikan dalam string posting.

Itu request.bodyhanyalah sebuah json ( {}) kosong .

Setelah banyak penyelidikan akhirnya ini berhasil untuk saya:

import { json } from 'body-parser';
...
app.use(json()); <-- should be defined before the first POST handler!

Mungkin juga penting untuk memberikan application/jsontipe konten dalam string permintaan dari sisi klien.

peterh - Kembalikan Monica
sumber
Saya minta maaf atas jawaban gaya "dan korbankan ayam hitam", yang sayangnya umum terjadi pada tahap lingkungan ketikan / node / sudut saat ini.
peterh
0

Sintaks untuk AngularJS v1.4.8 + (v1.5.0)

       $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );

Misalnya:

    var url = "http://example.com";

    var data = {
        "param1": "value1",
        "param2": "value2",
        "param3": "value3"
    };

    var config = {
        headers: {
            'Content-Type': "application/json"
        }
    };

    $http.post(url, data, config)
            .then(
                    function (response) {
                        // success callback
                    },
                    function (response) {
                        // failure callback
                    }
            );
Pranav VR
sumber