AngularJS - มีวิธีใดให้ $ http.post ส่งพารามิเตอร์คำขอแทน JSON?


116

ฉันมีรหัสเก่าที่สร้างคำขอ AJAX POST ผ่านวิธีการโพสต์ของ jQueryและมีลักษณะดังนี้:

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

requestData เป็นเพียงวัตถุจาวาสคริปต์ที่มีคุณสมบัติสตริงพื้นฐานบางอย่าง

ฉันกำลังดำเนินการย้ายข้อมูลของเราไปใช้ 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ให้ส่งวัตถุจาวาสคริปต์เป็นพารามิเตอร์คำขอแทน JSON หรือไม่ ใช่ฉันรู้ว่าฉันสามารถสร้างสตริงด้วยตัวเองจากออบเจ็กต์ได้ แต่ฉันอยากรู้ว่า Angular ให้อะไรมาจากกล่อง

คำตอบ:


140

ฉันคิดว่าparamsพารามิเตอร์ config จะไม่ทำงานที่นี่เนื่องจากเพิ่มสตริงลงใน url แทนที่จะเป็น body แต่เพื่อเพิ่มสิ่งที่ Infeligo แนะนำที่นี่คือตัวอย่างของการแทนที่ global ของการแปลงเริ่มต้น (โดยใช้ jQuery paramเป็นตัวอย่างในการแปลง ข้อมูลไปยังสตริงพารามิเตอร์)

ตั้งค่าฟังก์ชัน 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';

ตัวอย่างไม่ใช่ global transformRequest ต่อการโทร:

    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แล้วมันไม่ทำงานมีเงื่อนงำเกี่ยวกับสิ่งนี้หรือไม่?
Dfr

1
WRT กำหนดค่าทั่วโลกฉันก็มีปัญหาเช่นกัน เมื่อฉันพยายามทำโดยใช้ตัวอย่างข้อมูลที่ให้ไว้ที่นี่ฉันได้รับข้อผิดพลาดCannot read property "jquery" of undefined.ฉันจะแก้ไขได้อย่างไร PS การแปลงต่อการโทรทำงาน
kshep92

@ kshep92 สิ่งที่เกิดขึ้นคือฟังก์ชัน transformRequest ถูกเรียกตามคำร้องขอโดยไม่มีข้อมูลดังนั้น 'data' จึงไม่ถูกกำหนด ฉันเพิ่มยามก่อนที่จะ 'return $ .param (data);' แทรกสิ่งนี้เป็นบรรทัดแรกในฟังก์ชัน transformRequest: 'if (data === undefined) return data;' ดูการแก้ไขที่ฉันทำกับคำตอบ
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ส่วนหัว Content-Type ตามปกติที่คาดไว้กับคำขอ 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

โปรดทราบว่าใน Angular 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
});

คำตอบนี้ดีมาก กล่าวถึงปัญหาหลัก 2 ประการเกี่ยวกับโพสต์จากเชิงมุม ต้องตั้งค่าส่วนหัวให้ถูกต้องและคุณต้องจัดลำดับข้อมูล json หากคุณไม่ต้องการการสนับสนุน IE8 ให้ใช้ 1.4+ ขึ้นไป
mbokil

ฉันเพิ่งใช้สิ่งนี้และมันช่วยแก้ปัญหาที่ฉันพบในการโพสต์ แต่สิ่งนี้ยังเปลี่ยนวิธีการทำงานของโปรแกรมแก้ไขและดูเหมือนว่าจะทำให้การใช้งาน $ http.patch () ของฉันใช้งานไม่ได้ทั้งหมด
Mike Feltman

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

ตามฉันแล้วมันง่ายที่สุดและง่ายที่สุด ... อาจมีวิธีอื่นอีกมากมาย
Rohit Luthra

2

การปรับอย่างรวดเร็ว - สำหรับผู้ที่มีปัญหากับการกำหนดค่าส่วนกลางของฟังก์ชัน transformRequest นี่คือตัวอย่างข้อมูลที่ฉันใช้เพื่อกำจัดCannot read property 'jquery' of undefinedข้อผิดพลาด:

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


0

ฉันพบพฤติกรรมที่เป็นปัญหาหลายครั้งของทั้งหมดนี้ ฉันใช้มันจาก express (ไม่มีการพิมพ์) และ 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ประเภทเนื้อหาในสตริงคำขอจากฝั่งไคลเอ็นต์อาจเป็นสิ่งสำคัญ


ฉันขอโทษสำหรับคำตอบสไตล์ "และสังเวยไก่ดำ" สิ่งที่พบบ่อยในขั้นตอนปัจจุบันของสภาพแวดล้อม typescript / node / เชิงมุม
peterh - คืนสถานะ Monica

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
                    }
            );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.