ฉันจะโพสต์ข้อมูลแบบฟอร์ม urlencoded ด้วย $ http โดยไม่ต้อง jQuery ได้อย่างไร


195

ฉันยังใหม่กับ AngularJS และสำหรับการเริ่มต้นฉันคิดว่าจะพัฒนาแอปพลิเคชันใหม่โดยใช้ AngularJS เท่านั้น

ฉันพยายามโทร AJAX ไปยังฝั่งเซิร์ฟเวอร์โดยใช้$httpจากแอพเชิงมุมของฉัน

สำหรับการส่งพารามิเตอร์ฉันลองต่อไปนี้:

$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?
Kevin B

@KevinB: ขอโทษ .. ฉันทำการแก้ไขให้ถูกต้องแล้ว
Veer Shrivastav

@mritunjay: ขอโทษ .. ฉันทำการแก้ไขแล้ว .. ฉันพยายามเหมือนกัน
Veer Shrivastav

@Veer ทำงานได้หรือยังมีปัญหาอยู่หรือไม่
V31

คำตอบ:


409

ฉันคิดว่าคุณต้องทำคือการแปลงข้อมูลของคุณจากวัตถุไม่ให้เป็นสตริง JSON แต่เป็นพารามิเตอร์ URL

จากบล็อกเบน Nadel ของ

โดยค่าเริ่มต้นบริการ $ http จะเปลี่ยนคำขอออกโดยจัดลำดับข้อมูลเป็น JSON แล้วโพสต์ด้วยประเภทเนื้อหา "application / json" เมื่อเราต้องการโพสต์ค่าเป็นโพสต์ FORM เราจำเป็นต้องเปลี่ยนอัลกอริธึมการทำให้เป็นอนุกรมและโพสต์ข้อมูลด้วย content-type, "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 () {});

UPDATE

หากต้องการใช้บริการใหม่ที่เพิ่มเข้ามาด้วย 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
Alex Pavlov

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- serializer ที่ได้แรงบันดาลใจจาก jQuery's .param()( แนะนำ )

  2. $httpParamSerializer - serializer ที่ 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 verbose เพิ่มเติม


เป็นอย่างไร$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

เราจะใช้สิ่งนี้กับทรัพยากร $ ภายในโรงงานได้อย่างไร
stilllife

2
ควรเป็น$http.({...แทนที่จะเป็น '$http.post({...
Carlos Granados

@CarlosGranados ขอบคุณสำหรับการสังเกต แก้ไขคำผิดนี้ที่นี่และในการสาธิต Plunker
Boaz

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบหลังจากย้ายจาก jQuery ไปยัง AngularJS
zero298

4
นี่เป็นคำตอบเฉพาะของ AngularJS ที่ฉันต้องการ ฉันหวังว่าโปสเตอร์จะเลือกสิ่งนี้เป็นคำตอบที่ดีที่สุด
Marty Chang

61

ดูเหมือนว่าทั้งหมดนี้เป็น overkill (หรือไม่ทำงาน) ... เพียงทำสิ่งนี้:

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

11
ในที่สุดความรู้สึกร่วมกัน
jlewkovich

สิ่งนี้จะส่งคำขอโดยมีส่วนหัวประเภทเนื้อหาที่ไม่ถูกต้องหรือไม่?
Phil

มันใช้งานได้สำหรับฉัน ... ไม่แน่ใจว่าส่วนหัวเป็นอะไร แต่คำขอทำงานและได้รับอนุญาตให้ตรวจสอบสิทธิ์ได้สำเร็จ ทำไมคุณไม่ลองทดสอบและแจ้งให้เราทราบ
Serj Sagan

5
@Phil ฉันเดาว่ามันอาจขึ้นอยู่กับเซิร์ฟเวอร์ฉันได้รับคำขอที่ไม่ดีจนกว่าฉันจะเพิ่ม {ส่วนหัว: {'ประเภทเนื้อหา': 'แอปพลิเคชัน / x-www-form-urlencoded'}} เป็น config arg หรือใช้การจัดหา คอนสตรัค $ http (config) เหมือนคำตอบของ moices แสดงให้เห็น ทั้งสองวิธีนี้เหนือกว่าคำตอบที่ยอมรับได้เนื่องจากไม่แนะนำการแปลงเวทย์มนตร์บางอย่างและไม่ต้องการผู้ใช้บริการเสริมบางอย่าง ขอบคุณ!
นาย Bungle

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)ในการเข้ารหัสข้อมูลหรือพารามิเตอร์ของคุณจะได้รับความเสียหายหากผู้ใช้ป้อนค่าเช่น"&myCustomParam=1"
Ivan Hušnjak

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และ.errorcallbacks (ขณะที่พวกเขากำลังเลิกใช้)

  • จากไซต์ 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อาร์เรย์ว่าง!
Veer Shrivastav

นี่คือการเรียก $ 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);
});

4
คำตอบรหัสเท่านั้นไม่มีประโยชน์สำหรับชุมชน โปรดดูวิธีการตอบ
abpatil

1

จากเอกสาร$ httpนี้ควรใช้งานได้ ..

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

@ เควินฉันไม่แน่ใจเกี่ยวกับเรื่องนี้ แต่ .. เมื่อฉันพยายามส่งสตริงมันแสดงให้ฉันเห็นข้อผิดพลาด
Srinath


1
โปรดทราบว่าการส่งที่ถูกต้องheadersจะไม่ส่งผลกระทบต่อdataซึ่งยังจะต้องมี urlencoded ไม่ทางใดก็ทางหนึ่ง
โบอาซ

ข้อมูลยังคงถูกส่งใน json คุณต้องเข้ารหัสข้อมูลลงใน x-www-form-urlencoded เพียงแค่เพิ่มส่วนหัวไม่เพียงพอ
wendellmva

1

คุณต้องโพสต์วัตถุจาวาสคริปต์ธรรมดาไม่มีอะไรอื่น

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

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

ถ้าคุณมี php เป็น back-end คุณจะต้องทำการแก้ไขเพิ่มเติม .. เช็คเอาต์ลิงค์นี้เพื่อแก้ไข 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

สิ่งนี้ใช้ได้สำหรับฉัน ฉันใช้เชิงมุมสำหรับ front-end และ laravel php สำหรับ back-end ในโครงการของฉันเว็บเชิงมุมส่งข้อมูล json ไปยัง laravel back-end

นี่คือตัวควบคุมเชิงมุมของฉัน

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 back-end controller ของฉัน

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}

มีนามสกุลของ Chrome ที่เรียกว่าบุรุษไปรษณีย์ คุณสามารถใช้เพื่อทดสอบ URL แบ็คเอนด์ว่าทำงานหรือไม่ https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en

หวังว่าคำตอบของฉันจะช่วยคุณ

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