Як я розміщую форми форми, кодовані urlenc, за допомогою $ 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, див


41
Дякуємо, що не використовуєте JQuery!
OverMars

1
що робити, якщо мені потрібно подати дані про багатосторонні форми / форми?
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
нуль298

4
Це відповідь AngularJS, яку я шукав. Я хотів би, щоб плакат вибрав це як найкращу відповідь.
Марті Чанг

61

Все це виглядає як надмірне (або не працює) ... просто так:

$http.post(loginUrl, `username=${ encodeURIComponent(username) }` +
                     `&password=${ encodeURIComponent(password) }` +
                     '&grant_type=password'
).success(function (data) {

11
Нарешті якийсь здоровий глузд
jlewkovich

Чи не надішле це запит із неправильним заголовком типу вмісту?
Філ

Це працювало для мене ... не впевнений, що таке заголовок, але запит спрацював, і це дозволило успішно пройти автентифікацію. Чому б ти не перевірив це і не дай нам знати.
Serj Sagan

5
@Phil Я думаю, що це може залежати від сервера, я отримав поганий запит, поки я не додав {headers: {'Content-Type': 'application / x-www-form-urlencoded'}} як аргумент config або постачальницького використання показує відповідь конструктора $ 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 () {});

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";

Не отримуючи нічого. Я все ще отримав порожній $_POSTмасив!
Веер Шрівастав

це $ http-дзвінок у вашому контролері?
V31,

ще одна річ - це ваш сервер end 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);
});

4
Відповіді лише на код не корисні для громади. Подивіться, будь ласка, як відповісти
abpatil

1

З документів $ http це має працювати.

  $http.post(url, data,{headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
    .success(function(response) {
         // your code...
     });

@Kevin Я не впевнений у цьому, але ... ще раз, коли я спробував надсилати рядок, він показав мені помилку
Шрінат

@KevinB Fine..Я зрозумів ... я думаю, що заголовки потрібно змінити під час надсилання рядка .. 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


саме НЕ того, про що він просив, він спеціально запитав, як він може отримати їх як 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();

0

Це працювало для мене. Я використовую angular для переднього та laravel php для back-end. У моєму проекті кутова веб-адреса передає дані json в backrand 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-зворотного рівня laravel.

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

Це моя маршрутизація laravel

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

Результат у браузері -

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

Існує хромоване розширення, яке називається листоношею. Ви можете використовувати для тестування вашого бек-енд-адреси, працює він чи ні. https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

сподіваюся, моя відповідь допоможе тобі.

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