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.