Как отправить данные формы в формате urlencoded с помощью $ http без jQuery?

195

Я новичок в AngularJS, и для начала я подумал о разработке нового приложения с использованием только AngularJS.

Я пытаюсь сделать AJAX-вызов на стороне сервера, используя $httpмое приложение Angular.

Для отправки параметров я попробовал следующее:

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

Это работает, но также использует jQuery $.param. Для удаления зависимости от jQuery я попытался:

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

но это, казалось, потерпело неудачу. Тогда я попробовал params:

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

но это также, казалось, не удалось. Тогда я попробовал JSON.stringify:

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

Я нашел эти возможные ответы на мои квесты, но безуспешно. Я делаю что-то неправильно? Я уверен, что AngularJS обеспечит эту функциональность, но как?

Веер Шривастав
источник
Я не знаю, что является реальной проблемой, но вы попробовали это$http({method: 'post', url: URL, data: {username: $scope.userName, password: $scope.password}});
Mritunjay
1
Ваш первый метод должен работать, $scope.userNameопределен? почему ты не попробовал data: data?
Кевин Б.
@KevinB: извините .. Я сделал правильное редактирование.
Веер Шривастав,
@mritunjay: извините .. Я внес изменения .. Я пытался то же самое.
Веер Шривастав,
@ Veer это сработало или у тебя все еще есть проблемы?
V31

Ответы:

409

Я думаю, вам нужно преобразовать ваши данные из объекта не в строку JSON, а в URL-параметры.

Из блога Бена Наделя .

По умолчанию служба $ http преобразует исходящий запрос, сериализуя данные в виде JSON, а затем публикуя их с типом содержимого «application / json». Когда мы хотим опубликовать значение как публикацию FORM, нам нужно изменить алгоритм сериализации и опубликовать данные с типом содержимого "application / x-www-form-urlencoded".

Пример отсюда .

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

ОБНОВИТЬ

Чтобы использовать новые сервисы, добавленные в AngularJS V1.4, см.

allenhwkim
источник
41
Спасибо, что не используете JQuery!
OverMars
1
Что делать, если мне нужно отправить multipart / form-data?
Dejell
2
Пока угловое встраивает jqLite angular.element, вы можете простоreturn angular.element.param(obj);
Vicary
4
@Vicary Имейте в виду, что param () не реализован в jqLite - code.angularjs.org/1.3.14/docs/api/ng/function/angular.element
Алекс Павлов
1
это еще один путь var obj = {a: 1, b: 2}; Object.keys(obj).reduce(function(p, c) { return p.concat([encodeURIComponent(c) + "=" + encodeURIComponent(obj[c])]); }, []).join('&');
test30
137

Переменные кодирования URL, использующие только сервисы AngularJS

Начиная с версии AngularJS 1.4 и выше, две службы могут обрабатывать процесс кодирования данных url для запросов POST, устраняя необходимость манипулировать данными с transformRequestиспользованием или используя внешние зависимости, такие как jQuery:

  1. $httpParamSerializerJQLike- сериализатор, вдохновленный jQuery's .param()( рекомендуется )

  2. $httpParamSerializer - сериализатор, используемый самой Angular для GET-запросов

Пример использования

$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 */ });

Посмотреть более подробную демоверсию Plunker


Как бывают $httpParamSerializerJQLikeи $httpParamSerializerразные

В общем, кажется, что он $httpParamSerializerиспользует менее «традиционный» формат кодирования url, чем $httpParamSerializerJQLikeкогда речь идет о сложных структурах данных.

Например (игнорирование процентного кодирования скобок):

Кодирование массива

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

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

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

Кодирование объекта

{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
Боаз
источник
Как мы можем использовать это на $ ресурсе внутри фабрики?
Натюрморт
2
Должно быть $http.({...вместо`$http.post({...
Карлос Гранадос
@CarlosGranados Спасибо, что заметили. Исправлена ​​эта опечатка здесь и в демоверсии Plunker.
Вооз
Это отлично работало после перехода с jQuery на AngularJS
zero298
4
Это специфичный для AngularJS ответ, который я искал. Я хотел бы, чтобы плакат выбрал это как лучший ответ.
Марти Чанг
61

Все это выглядит как излишнее (или не работает) ... просто сделайте это:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {
Серж Саган
источник
11
Наконец , некоторые здравый смысл
jlewkovich
Разве это не отправит запрос с неправильным заголовком типа контента?
Фил
Он работал для меня ... не уверен, что заголовок был, но запрос работал, и это позволило успешно аутентифицироваться. Почему бы вам не проверить это и сообщить нам.
Серж Саган
5
@Phil Я думаю, это может зависеть от сервера, я получил неверный запрос, пока не добавил {headers: {'Content-Type': 'application / x-www-form-urlencoded'}} в качестве аргумента конфигурации или использования предложения $ http (config) конструктор, как показывает ответ moices. В любом случае это превосходит принятый ответ, поскольку он не вводит магического преобразования и не требует от пользователя какого-либо вспомогательного обслуживания. Спасибо!
Мистер Бангла
23

Проблема в формате строки JSON. Вы можете использовать простую строку URL в данных:

$http({
    method: 'POST',
    url: url,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    data: 'username='+$scope.userName+'&password='+$scope.password
}).success(function () {});
moices
источник
7
Вы должны использовать encodeURIComponent($scope.userName)URL для кодирования данных, иначе ваши параметры будут повреждены, если пользователь "&myCustomParam=1"
введет
2
это единственный ответ, который сработал для меня! Я пропустил успех, но формат $ http хорош
xenteros
4

Вот как это должно быть (и, пожалуйста, не вносите никаких изменений в бэкэнд ... конечно, нет ... если ваш передний стек не поддерживает application/x-www-form-urlencoded, то выбросьте его ... надеюсь AngularJS!

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

Работает как шарм с AngularJS 1.5

Люди, давайте дадим вам несколько советов:

  • использовать обещания .then(success, error)при работе с ними $http, забывать о них .sucessи .errorобратные вызовы (так как они устарели)

  • С сайта angularjs здесь: « Вы больше не можете использовать строку JSON_CALLBACK в качестве заполнителя для указания, куда должно идти значение параметра обратного вызова ».

Если ваша модель данных более сложна, чем просто имя пользователя и пароль, вы все равно можете это сделать (как предложено выше)

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

Документ на это encodeURIComponentможно найти здесь

Махиеддин М. Ичир
источник
3

Если это форма, попробуйте изменить заголовок на:

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

и если это не форма, а простой json, попробуйте этот заголовок:

headers[ "Content-type" ] = "application/json";
V31
источник
Ничего не получаю. Я все еще получил пустой $_POSTмассив.
Веер Шривастав
это вызов $ http в вашем контроллере?
V31
еще одна вещь, ваш сервер php?
V31
Я нашел решение для того же, вы все еще получаете проблему @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);
});
user8483090
источник
4
Ответы только на код не полезны для сообщества. Пожалуйста, посмотрите на Как ответить
abpatil
1

Из документов $ http это должно работать ..

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });
Srinath
источник
@Kevin Я не уверен в этом, но .. как только я попытался отправить строку, это показало мне ошибку
Srinath
@KevinB Хорошо .. Я понял .. я думаю, что заголовки нужно менять при отправке строки .. stackoverflow.com/a/20276775/2466168
Сринат
1
Обратите внимание, что отправка правильного headersне повлияет на то, dataчто все равно нужно будет кодировать, так или иначе.
Вооз
данные по-прежнему отправляются в формате json. Вы должны закодировать данные в x-www-form-urlencoded. Недостаточно просто добавить заголовок
wendellmva
1

вам нужно опубликовать простой объект JavaScript, ничего больше

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

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

если у вас есть php в качестве бэк-энда, вам нужно будет сделать еще некоторые изменения. Проверьте эту ссылку для исправления php сервера

harishr
источник
это точно НЕ то, что он просил, он специально спросил, как он может получить их как x-www-form-urlencoded, потому что он сталкивается с проблемами с размещенными материалами json.
ppetermann
@ppetermann вы проверили историю редактирования вопроса, прежде чем понизить голосование ..
harishr
1

Несмотря на поздний ответ, я обнаружил, что угловой UrlSearchParams работает очень хорошо для меня, он также заботится о кодировании параметров.

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
источник
0

Это сработало для меня. Я использую угловой для front-end и laravel php для back-end. В моем проекте angular web отправляет данные json на серверную часть laravel.

Это мой угловой контроллер.

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

});

Это мой php back-end контроллер laravel.

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

Это мой маршрут

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

Результат в браузере


данные состояния 200 JSON_CALLBACK ({"имя пользователя": "Виктория", "пароль": "пароль", "обратный вызов": "JSON_CALLBACK"}); httpTesting.js: функция 18 заголовков (c) {a || (a = sc (b)); вернуть c? a [K (c)] || null: a}

Существует расширение Chrome под названием почтальон. Вы можете использовать для проверки вашего внутреннего URL, работает ли он или нет. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

надеюсь, мой ответ поможет вам.

meazuri
источник