AngularJS - Будь-який спосіб для $ http.post надсилати параметри запиту замість JSON?


116

У мене є старий код, який робить запит AJAX POST методом публікації jQuery і виглядає приблизно так:

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

requestData це лише об’єкт javascript з деякими основними властивостями рядків.

Я зараз переношу наші матеріали, щоб використовувати Angular, і я хочу замінити цей дзвінок на $ http.post. Я придумав таке:

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

Коли я це зробив, я отримав відповідь на помилку 500 від сервера. Використовуючи Firebug, я виявив, що це надіслало такий запит:

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

Успішний jQuery $.postнадсилає тіло так:

param1=value1&param2=value2&param3=value3

Кінцева точка, в яку я потрапляю, очікує параметрів запиту, а не JSON. Отже, моє запитання: чи все-таки потрібно сказати, $http.postщоб надіслати об’єкт javascript як параметри запиту замість JSON? Так, я знаю, що міг би сконструювати рядок самостійно з об'єкта, але я хочу знати, чи надає Angular щось для цього поза полем.

Відповіді:


140

Я думаю, що paramsпараметр config не буде працювати тут, оскільки він додає рядок до URL-адреси замість тіла, але для додавання до запропонованого тут Infeligo є прикладом глобального переопрацювання перетворення за замовчуванням (використовуючи параметр jQuery як приклад для перетворення дані в парам).

Налаштуйте глобальну функцію transformRequest:

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

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

Таким чином, всі виклики на $ http.post автоматично перетворять тіло у той самий формат парам, який використовується у $.postвиклику jQuery .

Зауважте, ви також можете встановити заголовок типу вмісту на виклик або так, як у всьому світі:

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

Зразок неглобальної трансформації Запит на виклик:

    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
    });

Мені було цікаво, чи є щось інше, ніж функція transformRequest, але це здається, що її немає. Дякуємо, що розповіли про функцію параметри jQuery.
dnc253

Неглобальний метод за один виклик працює для мене добре, але коли намагаються налаштувати глобально через $httpProvider.defaults, то він не працює, якийсь підказки про це?
Дфр

1
Налаштувавши WRT глобально, у мене теж виникають проблеми. Коли я намагаюся зробити це за допомогою наведеного тут фрагмента, я отримую помилку Cannot read property "jquery" of undefined.Як це виправити? PS. Перетворення за викликом працюють.
kshep92

@ kshep92 Що відбувається, це те, що функція transformRequest викликає запит без даних, тому "data" не визначено. Я додав захист до 'return $ .param (data);'. Вставте це як перший рядок до функції transformRequest: 'if (data === undefined) повертає дані;' Дивіться правку, яку я зробив у відповідь.
Jere.Jones

1
станом на Angular 1.4 ви можете використовувати $ httpParamSerializer замість jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
theRemix

21

Якщо ви використовуєте Angular> = 1.4 , ось найчистіше рішення, яке я знайшов і не покладається ні на що на замовлення чи зовнішнє:

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';
});

І тоді ви можете це зробити в будь-якому місці вашого додатка:

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

І він буде правильно серіалізувати дані як param1=value1&param2=value2і надсилати їх /requesturlіз application/x-www-form-urlencoded; charset=utf-8заголовком типу вмісту, як це зазвичай очікується при запитах POST на кінцевих точках.


17

З документації AngularJS:

params - {Object.} - карта рядків або об'єктів, на які буде перетворено? key1 = value1 & key2 = value2 після URL-адреси. Якщо значення не є рядком , воно буде JSONified.

Отже, наведіть рядок як параметри. Якщо ви цього не хочете, використовуйте перетворення. Знову з документації:

Щоб локально змінити ці перетворення, вкажіть функції перетворення як властивості transformRequest та / або transformResponse об’єкта config. Щоб глобально змінити перетворення за замовчуванням, замініть властивості $ httpProvider.defaults.transformRequest та $ httpProvider.defaults.transformResponse $ httpProvider.

Детальнішу інформацію див. У документації .


Я бачив парами в документації, і, як згадує Gloopy, мені це потрібно в тілі, а не за URL-адресою. Мені було цікаво, чи є якийсь варіант чи щось мені не вистачало для виконання параметрів замість JSON, але це звучить так, що мені просто потрібно використовувати властивість transformRequest.
dnc253

15

Використовуйте $.paramфункцію jQuery для серіалізації даних JSON у requestData.

Словом, використовуючи аналогічний код, як і ваш:

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

Щоб використовувати це, вам потрібно включити jQuery на свою сторінку разом з AngularJS.


7

Зауважте, що з кутового 1.4 ви можете серіалізувати дані форми, не використовуючи jQuery.

У app.js:

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

Потім у своєму контролері:

$http({
    method: 'POST',
    url: myUrl',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: myData
});

Ця відповідь чудова. У ньому розглядаються дві основні проблеми з Post from Angular. Заголовок повинен бути встановлений правильно, і вам доведеться серіалізувати дані json. Якщо вам не потрібна підтримка IE8, використовуйте версію 1.4 або новішу.
mbokil

Я щойно реалізував це, і це вирішує проблеми, які виникали у мене з повідомленням, але це також змінює спосіб роботи патча і, здається, порушив усі мої використання $ http.patch ().
Майк Фельтман

5

Це може бути трохи злому, але я уникнув проблеми і перетворив json в масив POST PHP на стороні сервера:

$_POST = json_decode(file_get_contents('php://input'), true);

Я використовував цей метод, але ненавиджу його; і мені знадобилося багато часу, щоб зрозуміти, чому я повинен цим користуватися.
meconroy

як я вже сказав, - це відчувається хакі. Як і більшість php;)
TimoSolo

5

У мене також проблеми з налаштуванням користувальницької автентифікації http, оскільки $ resource кешує запит.

Для цього вам потрібно перезаписати існуючі заголовки, зробивши це

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'}
      },
    }
);

Сподіваюся, мені вдалося комусь допомогти. На це мені знадобилося 3 дні.


Я думаю, ти щойно врятував мені 3 дні роботи. Дякую!!! Я все ще намагаюся зрозуміти, чи зможу я якось перехопити запит на виклик, щоб я міг ввести спеціальний заголовок для кожного дзвінка.
marcoseu

4

Змініть заголовки за замовчуванням:

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

Потім використовуйте $.paramметод JQuery :

var payload = $.param({key: value});
$http.post(targetURL, payload);

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 () {});
    }
  ]);

На мою думку, найпростіший і найпростіший ... Можливо, ще багато інших способів
Рохіт Лютра

2

Швидке налаштування - для тих, хто має проблеми з глобальною конфігурацією функції transformRequest, ось фрагмент, який я використовую, щоб позбутися від Cannot read property 'jquery' of undefinedпомилки:

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


0

Я багато разів знаходив проблематичну поведінку цього цілого. Я використовував це з експресу (без типізації) та bodyParser (з типізацією dt ~ body-parser).

Я не намагався завантажувати файл, а просто інтерпретувати JSON, поданий у рядку повідомлення.

Це request.bodyбув просто порожній json ( {}).

Після багатьох розслідувань нарешті це спрацювало для мене:

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

Також може бути важливим надати application/jsonтип вмісту в рядку запиту від клієнтської сторони.


Мені шкода за відповідь "і принести в жертву чорну курку", що, на жаль, часто зустрічається на поточному етапі машинописного тексту / вузла / кутового середовища.
петерх

0

Синтаксис для AngularJS v1.4.8 + (v1.5.0)

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

Наприклад:

    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
                    }
            );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.