AngularJS - Có cách nào để $ http.post gửi các tham số yêu cầu thay vì JSON không?


116

Tôi có một số mã cũ đang thực hiện yêu cầu AJAX POST thông qua phương thức đăng của jQuery và trông giống như sau:

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

requestData chỉ là một đối tượng javascript với một số thuộc tính chuỗi cơ bản.

Tôi đang trong quá trình chuyển nội dung của chúng tôi sang sử dụng Angular và tôi muốn thay thế cuộc gọi này bằng $ http.post. Tôi đã nghĩ ra những điều sau:

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

Khi tôi thực hiện việc này, tôi nhận được phản hồi lỗi 500 từ máy chủ. Bằng cách sử dụng Firebug, tôi thấy rằng điều này đã gửi phần thân yêu cầu như sau:

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

JQuery thành công $.postsẽ gửi phần thân như sau:

param1=value1&param2=value2&param3=value3

Điểm cuối tôi đang đánh là mong đợi các thông số yêu cầu chứ không phải JSON. Vì vậy, câu hỏi của tôi là có cách nào để $http.postyêu cầu gửi đối tượng javascript dưới dạng tham số yêu cầu thay vì JSON không? Có, tôi biết tôi có thể tự mình xây dựng chuỗi từ đối tượng, nhưng tôi muốn biết liệu Angular có cung cấp bất kỳ thứ gì cho điều này không.

Câu trả lời:


140

Tôi nghĩ rằng paramstham số cấu hình sẽ không hoạt động ở đây vì nó thêm chuỗi vào url thay vì nội dung nhưng để thêm vào những gì Infeligo đề xuất ở đây là một ví dụ về ghi đè toàn cục của một biến đổi mặc định (sử dụng jQuery param làm ví dụ để chuyển đổi dữ liệu thành chuỗi tham số).

Thiết lập hàm biến đổi toàn cục:

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

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

Bằng cách đó, tất cả các lệnh gọi tới $ http.post sẽ tự động chuyển đổi phần thân sang cùng một định dạng tham số được sử dụng bởi lệnh $.postgọi jQuery .

Lưu ý rằng bạn cũng có thể muốn đặt tiêu đề Loại-Nội dung cho mỗi cuộc gọi hoặc trên toàn cầu như thế này:

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

Mẫu chuyển đổi không toàn cục Yêu cầu mỗi cuộc gọi:

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

Tôi đã tự hỏi liệu có điều gì khác ngoài việc có một hàm biến đổi, nhưng có vẻ như không có. Cảm ơn bạn đã biết về hàm param jQuery.
dnc253,

Phương thức không toàn cục cho mỗi cuộc gọi đang hoạt động tốt đối với tôi, nhưng khi cố gắng thiết lập toàn cục thông qua $httpProvider.defaults, thì nó không hoạt động, bất kỳ manh mối nào về điều này?
Dfr

1
WRT định cấu hình nó trên toàn cầu, tôi cũng đang gặp sự cố. Khi tôi cố gắng thực hiện việc đó bằng đoạn mã được cung cấp ở đây, tôi gặp lỗi Cannot read property "jquery" of undefined.Làm cách nào để khắc phục lỗi này? Tái bút. Các phép biến đổi mỗi cuộc gọi hoạt động.
kshep92

@ kshep92 Điều gì đang xảy ra là hàm biến đổi đang được gọi theo yêu cầu không có dữ liệu nên 'dữ liệu' là không xác định. Tôi đã thêm một bảo vệ trước khi 'return $ .param (data);'. Chèn dòng này làm dòng đầu tiên cho hàm biến đổi: 'if (data === undefined) return data;' Xem chỉnh sửa tôi đã thực hiện cho câu trả lời.
Jere.Jones

1
kể từ Angular 1.4, bạn có thể sử dụng $ httpParamSerializer thay vì jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
theRemix

21

Nếu sử dụng Angular> = 1.4 , đây là giải pháp sạch nhất mà tôi đã tìm thấy mà không dựa vào bất kỳ thứ gì tùy chỉnh hoặc bên ngoài:

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

Và sau đó bạn có thể thực hiện việc này ở bất kỳ đâu trong ứng dụng của mình:

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

Và nó sẽ tuần tự hóa dữ liệu một cách chính xác param1=value1&param2=value2và gửi nó đến /requesturlvới application/x-www-form-urlencoded; charset=utf-8tiêu đề Loại-Nội dung như thường được mong đợi với các yêu cầu ĐĂNG trên điểm cuối.


17

Từ tài liệu AngularJS:

params - {Object.} - Bản đồ các chuỗi hoặc đối tượng sẽ được chuyển thành? key1 = value1 & key2 = value2 sau url. Nếu giá trị không phải là một chuỗi , nó sẽ được JSON hóa.

Vì vậy, hãy cung cấp chuỗi dưới dạng tham số. Nếu bạn không muốn điều đó, thì hãy sử dụng phép biến hình. Một lần nữa, từ tài liệu:

Để ghi đè cục bộ các phép chuyển đổi này, hãy chỉ định các hàm biến đổi dưới dạng các thuộc tính Biến đổi và / hoặc Biến đổiResponse của đối tượng cấu hình. Để ghi đè toàn cục các chuyển đổi mặc định, hãy ghi đè các thuộc tính $ httpProvider.defaults.transformRequest và $ httpProvider.defaults.transformResponse của $ httpProvider.

Tham khảo tài liệu để biết thêm chi tiết.


Tôi đã thấy các thông số trong tài liệu và giống như Gloopy đã đề cập, tôi cần nó trong nội dung chứ không phải trên URL. Tôi đã tự hỏi nếu có một số tùy chọn hoặc điều gì đó tôi thiếu để thực hiện các tham số thay vì JSON, nhưng có vẻ như tôi chỉ cần sử dụng thuộc tính biến đổi.
dnc253,

15

Sử dụng $.paramhàm của jQuery để tuần tự hóa dữ liệu JSON trong requestData.

Tóm lại, sử dụng mã tương tự như của bạn:

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

Để sử dụng điều này, bạn phải bao gồm jQuery trong trang của mình cùng với AngularJS.


7

Lưu ý rằng kể từ Angular 1.4, bạn có thể tuần tự hóa dữ liệu biểu mẫu mà không cần sử dụng jQuery.

Trong app.js:

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

Sau đó, trong bộ điều khiển của bạn:

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

Câu trả lời này là tuyệt vời. Nó giải quyết 2 vấn đề chính với Post from Angular. Tiêu đề phải được đặt chính xác và bạn phải tuần tự hóa dữ liệu json. Nếu bạn không cần hỗ trợ IE8, hãy sử dụng phiên bản 1.4+ trở lên.
mbokil

Tôi vừa triển khai điều này và nó giải quyết các vấn đề tôi gặp phải với bài đăng, nhưng điều này cũng thay đổi cách hoạt động của bản vá và dường như đã phá vỡ tất cả các hoạt động sử dụng $ http.patch () của tôi.
Mike Feltman

5

Đây có thể là một chút hack, nhưng tôi đã tránh được sự cố và chuyển đổi json thành mảng POST của PHP ở phía máy chủ:

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

Tôi đã sử dụng phương pháp này, nhưng tôi ghét nó; và tôi mất nhiều thời gian để tìm ra lý do tại sao tôi phải sử dụng cái này.
meconroy

như tôi đã nói - nó cảm thấy khó hiểu. Giống như hầu hết các php;)
TimoSolo

5

Tôi cũng gặp sự cố với việc đặt xác thực http tùy chỉnh vì $ resource lưu vào bộ nhớ cache yêu cầu.

Để làm cho nó hoạt động, bạn phải ghi đè các tiêu đề hiện có bằng cách thực hiện điều này

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

Tôi hy vọng tôi đã có thể giúp một ai đó. Tôi đã mất 3 ngày để tìm ra điều này.


Tôi đoán bạn vừa tiết kiệm cho tôi 3 ngày làm việc. Cảm ơn!!! Tôi vẫn đang cố gắng tìm hiểu xem liệu tôi có thể chặn cuộc gọi yêu cầu bằng cách nào đó để tôi có thể đưa tiêu đề tùy chỉnh cho mọi cuộc gọi hay không.
marcoseu

4

Sửa đổi các tiêu đề mặc định:

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

Sau đó, sử dụng $.paramphương thức của 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 () {});
    }
  ]);

Theo tôi nó đơn giản nhất và dễ dàng nhất ... Có thể có nhiều cách khác
Rohit Luthra

2

Điều chỉnh nhanh - đối với những bạn gặp sự cố với cấu hình chung của hàm biến đổi, đây là đoạn mã tôi đang sử dụng để loại bỏ Cannot read property 'jquery' of undefinedlỗi:

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


0

Tôi đã tìm thấy nhiều lần hành vi có vấn đề của toàn bộ này. Tôi đã sử dụng nó từ express (không có kiểu chữ) và bodyParser (với kiểu chữ dt ~ body-parser).

Tôi đã không cố gắng tải lên một tệp, thay vào đó chỉ đơn giản là để diễn giải một JSON được cung cấp trong một chuỗi bài đăng.

Đơn request.bodygiản là một json ( {}) trống .

Sau rất nhiều cuộc điều tra cuối cùng điều này đã làm việc cho tôi:

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

Nó cũng có thể quan trọng để cung cấp application/jsonloại nội dung trong chuỗi yêu cầu từ phía máy khách.


Tôi xin lỗi vì câu trả lời kiểu "và hy sinh một con gà mái đen", điều không may là phổ biến trong giai đoạn hiện tại của môi trường sắp chữ / nút / góc.
peterh - Phục hồi Monica

0

Cú pháp cho AngularJS v1.4.8 + (v1.5.0)

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

Ví dụ:

    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
                    }
            );
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.