요청 페이로드 대신 데이터를 양식 데이터로 게시하려면 어떻게해야합니까?


523

아래 코드에서 AngularJS $http메소드는 URL을 호출하고 xsrf 객체를 "요청 페이로드"(Chrome 디버거 네트워크 탭에 설명 된대로)로 제출합니다. jQuery $.ajax메소드는 동일한 호출을 수행하지만 xsrf를 "양식 데이터"로 제출합니다.

AngularJS가 요청 페이로드 대신 xsrf를 양식 데이터로 제출하도록하려면 어떻게해야합니까?

var url = 'http://somewhere.com/';
var xsrf = {fkey: 'xsrf key'};

$http({
    method: 'POST',
    url: url,
    data: xsrf
}).success(function () {});

$.ajax({
    type: 'POST',
    url: url,
    data: xsrf,
    dataType: 'json',
    success: function() {}
});

1
이것은 매우 유용한 질문이었습니다. 페이로드를 문자열로 보내 (Content-Type을 변경하여) POST / GET 이전에 OPTIONS를 처리하지 않아도됩니다.
earthmeLon

나는 같은 질문이 있는데, 그것은 URL을 요청한 후에이다. 그러나 나는 내가 제출 한 매개 변수를 얻을 수 없다
黄伟杰

답변:


614

전달 된 $ http 객체에 다음 줄을 추가해야합니다.

headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}

그리고 전달 된 데이터는 URL 인코딩 문자열로 변환되어야합니다.

> $.param({fkey: "key"})
'fkey=key'

따라서 다음과 같은 것이 있습니다.

$http({
    method: 'POST',
    url: url,
    data: $.param({fkey: "key"}),
    headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})

보낸 사람 : https://groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ

최신 정보

AngularJS V1.4에 추가 된 새로운 서비스를 사용하려면


3
데이터의 json> url 인코딩이 자동으로 발생하거나 모든 POST 또는 PUT 메소드에 대해이를 지정하는 방법이 있습니까?
Dogoku

51
+1 @mjibson, 나에게도 헤더를 전달해도 작동하지 않습니다. 귀하의 답변이 포함되어 var xsrf = $.param({fkey: "key"});있습니다.
naikus

12
$ .ajax 기본 동작을 더 가깝게 따르려면 콘텐츠 유형 헤더에 – 문자를 지정해야합니다 –headers: {Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
Imre

25
대신 jQuery의 PARAM 기능을 사용하는 단지 $ HTTP 요청에 PARAMS 속성을 설정하고이 jQuery.param 방법은 한 Content-Type 헤더는 '응용 프로그램 / x-www-form-urlencoded를'있는 그대로 무엇을 할 것입니다 - 유래는 .com / questions / 18967307 /…
spig

13
@spig 예, jQuery.param이 수행하는 작업을 수행하지만 params 속성을 사용하면 application / x-www-를 지정한 경우에도 속성이 본문 대신 요청 URL의 일부로 인코딩됩니다. 양식 URI 헤더.
stian April

194

솔루션에서 jQuery를 사용하지 않으려면 시도해보십시오. 해결책은 여기에서 https : //.com/a/1714899/1784301

$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: xsrf
}).success(function () {});

7
이 방법은 angular 1.2.x에서 저에게 효과적이며, 우아하고 핵심 각도에서 작동하며 jQuery와 같은 외부 라이브러리에 의존하지 않기 때문에 가장 좋은 대답이라고 생각합니다.
gregtczap

2
$ resource 작업 내에서이 방법을 사용할 때 문제가 발생했습니다. 양식 데이터에는 $ get, $ save 등의 함수도 포함되어있었습니다. 솔루션은 대신 for사용 하도록 명령문을 약간 변경하는 것이 었습니다 angular.forEach.
Anthony

10
$ .param ()과 달리이 메소드는 배열 / 객체에서 재귀 적으로 작동하지 않습니다.
MazeChaZer

1
null 또는 undefinedobj[p] 가 아닌지 확인합니다 . 그렇지 않으면 "null"또는 "undefined"문자열을 값으로 전송하게됩니다.
타 미르

1
이해하지 못했습니다 transformRequest: function(obj)obj가 정의되지 않았으므로 xsrf를 전달한다고 가정합니까? 처럼transformRequest: function(xsrf)
Akshay Taru

92

이 문제를 둘러싼 혼란은 계속해서 블로그 게시물을 작성하도록 영감을주었습니다. 이 게시물에서 제안하는 솔루션은 $ http 서비스 호출을 위해 데이터 객체를 매개 변수화하는 것을 제한하지 않기 때문에 현재 최고 등급 솔루션보다 낫습니다. 즉 내 솔루션을 사용하면 실제 데이터 객체를 계속 $ http.post () 등에 전달하고 원하는 결과를 얻을 수 있습니다.

또한 최고 등급의 답변은 $ .param () 함수의 페이지에 전체 jQuery를 포함시키는 것에 의존하지만 내 솔루션은 jQuery에 독립적이며 순수한 AngularJS가 준비되어 있습니다.

http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

도움이 되었기를 바랍니다.


10
자세한 블로그는 +1이지만, 이것이 필요하다는 사실은 끔찍합니다 ...
iwein

4
예, 아마도 두 가지 수준에서 끔찍할 수 있습니다 : 1) AngularJS는 사실상 (잘못 안내되지는 않았지만) 표준 을 뒤집기로 결정했습니다 .2) PHP (및 다른 서버 측 언어를 아는 사람)는 어떻게 든 자동으로 응용 프로그램 / json을 감지하지 못합니다 입력. : P
에스겔 빅터

angularjs가 콘텐츠 유형에 자동으로 적응하고 그에 따라 인코딩 할 수 있습니까? 예견 되었습니까?
unludo

4
나는 (다른 많은 사람들과 마찬가지로) 내 백엔드 ASP.NET가 이것을 기본적으로 지원하지 않았다는 것을 알게되었습니다 . AngularJS의 동작을 변경하지 않으려는 경우 (내 API가 JSON을 반환하기 때문에 JSON을 허용하지 않는 이유는 양식 데이터보다 더 유연합니다) 읽을 수 Request.InputStream있고 어떤 식 으로든 처리 할 수 ​​있습니다 당신이 원하는. ( dynamic사용하기 쉽 도록 역 직렬화하기로 선택했습니다 .)
Aidiakapi

2
이것은 독립적 인 답변이 아니기 때문에 다운 보트되었습니다 . 좋은 답변은 다른 곳으로 연결되지 않습니다. 에서 어떻게하면 답변합니다 : "항상 대상 사이트에 연결할 수 또는 영구적으로 오프라인이 경우 중요한 링크의 대부분의 관련 부분을 인용."
제임스

83

나는 다른 답변을 몇 가지 가지고 조금 더 깨끗하게 만들었습니다 .config().app.js의 angular.module 끝에이 호출을 넣으 십시오.

.config(['$httpProvider', function ($httpProvider) {
  // Intercept POST requests, convert to standard form encoding
  $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
  $httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
    var key, result = [];

    if (typeof data === "string")
      return data;

    for (key in data) {
      if (data.hasOwnProperty(key))
        result.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
    }
    return result.join("&");
  });
}]);

1
자원 정의에 추가 된 경우에도 매력처럼 작동합니다.
Kai Mattern

3
또한 unshift()다른 변형이 방해받지 않도록 사용 하도록 주의를 기울 였습니다. 잘 했어.
Aditya MP

2
완전한! 나를 위해 잘 작동했습니다! 슬픈 각도는 기본적으로 이것을 지원하지 않습니다.
spierala

2
이 답변은 상단에 올바른 답변이어야하며 다른 답변은 잘못되었습니다.
Jose Ignacio Hita 2016 년

2
재귀 인코딩은 어떻습니까?
Petah

58

AngularJS v1.4.0부터는 문서 페이지$httpParamSerializer 에 나열된 규칙에 따라 객체를 HTTP 요청의 일부로 변환 하는 기본 제공 서비스가 있습니다 .

다음과 같이 사용할 수 있습니다 :

$http.post('http://example.com', $httpParamSerializer(formDataObj)).
    success(function(data){/* response status 200-299 */}).
    error(function(data){/* response status 400-999 */});

올바른 양식 게시물의 경우 Content-Type헤더를 변경해야합니다. 모든 POST 요청에 대해 전체적으로이 작업을 수행하기 위해이 코드 (Albireo의 반 답변에서 가져온)를 사용할 수 있습니다.

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

현재 게시물에 대해서만이 작업을 수행하려면 headersrequest-object 의 속성을 수정해야합니다.

var req = {
 method: 'POST',
 url: 'http://example.com',
 headers: {
   'Content-Type': 'application/x-www-form-urlencoded'
 },
 data: $httpParamSerializer(formDataObj)
};

$http(req);

커스텀 $ resource 팩토리에서 어떻게 똑같이 할 수 있습니까?
stilllife

참고 : 앱을 Angular 1.3에서 1.5로 업그레이드했습니다. transformRequest에서 헤더를 변경했습니다. 어떤 이유로 든 위의 방법이 효과가 없다면 Angular는 URL 인코딩 문자열 주위에 큰 따옴표를 추가합니다. 로 해결되었습니다 transformRequest: $httpParamSerializer, data: formDataObj. 솔루션 주셔서 감사합니다.
PhiLho

24

전역 적으로 동작을 정의 할 수 있습니다.

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

따라서 매번 재정의하지 않아도됩니다.

$http.post("/handle/post", {
    foo: "FOO",
    bar: "BAR"
}).success(function (data, status, headers, config) {
    // TODO
}).error(function (data, status, headers, config) {
    // TODO
});

46
귀하의 예가 잘못되었습니다 ... 수정하는 것은 헤더뿐입니다. 데이터 자체는 여전히 JSON으로 인코딩되며 JSON을 읽을 수없는 이전 서버에서는 읽을 수 없습니다.
alexk

victorblog.com/2012/12/20/…-$ http 기본 헤더를 재정의하고 개체를 직렬화 된 양식 데이터로 변환하는 좋은 예입니다.
Federico

20

임시 해결책으로 POST를 수신하는 코드가 애플리케이션 / json 데이터에 응답하도록 만들 수 있습니다. PHP의 경우 아래 코드를 추가하여 양식 인코딩 또는 JSON으로 POST 할 수 있습니다.

//handles JSON posted arguments and stuffs them into $_POST
//angular's $http makes JSON posts (not normal "form encoded")
$content_type_args = explode(';', $_SERVER['CONTENT_TYPE']); //parse content_type string
if ($content_type_args[0] == 'application/json')
  $_POST = json_decode(file_get_contents('php://input'),true);

//now continue to reference $_POST vars as usual

이 문제에 대한 진짜 문제는 서버 측 API에 있기 때문에이 서버 쪽 수정의 좋은 예 중 하나입니다 .. 브라보
인 Vignesh

16

이 답변은 미친듯한 과잉처럼 보이며 때로는 단순한 것이 더 좋습니다.

$http.post(loginUrl, "userName=" + encodeURIComponent(email) +
                     "&password=" + encodeURIComponent(password) +
                     "&grant_type=password"
).success(function (data) {
//...

1
나를 위해 여전히 헤더를 지정 Content-Type하고로 설정해야했습니다 application/x-www-form-urlencoded.
Victor Ramos

9

아래 솔루션으로 시도해 볼 수 있습니다

$http({
        method: 'POST',
        url: url-post,
        data: data-post-object-json,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        transformRequest: function(obj) {
            var str = [];
            for (var key in obj) {
                if (obj[key] instanceof Array) {
                    for(var idx in obj[key]){
                        var subObj = obj[key][idx];
                        for(var subKey in subObj){
                            str.push(encodeURIComponent(key) + "[" + idx + "][" + encodeURIComponent(subKey) + "]=" + encodeURIComponent(subObj[subKey]));
                        }
                    }
                }
                else {
                    str.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]));
                }
            }
            return str.join("&");
        }
    }).success(function(response) {
          /* Do something */
        });

8

게시 할 어댑터 서비스를 작성하십시오.

services.service('Http', function ($http) {

    var self = this

    this.post = function (url, data) {
        return $http({
            method: 'POST',
            url: url,
            data: $.param(data),
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
    }

}) 

컨트롤러 또는 다음에서 사용하십시오.

ctrls.controller('PersonCtrl', function (Http /* our service */) {
    var self = this
    self.user = {name: "Ozgur", eMail: null}

    self.register = function () {
        Http.post('/user/register', self.user).then(function (r) {
            //response
            console.log(r)
        })
    }

})

jquery abi에서만 $ .param. jsfiddle.net/4n9fao9q/27 $ httpParamSerializer는 Angularjs와 동일합니다.
덱스터

7

이것과 다른 관련 자료 -AJAX 양식 제출 : AngularJS Way을 ​​다루는 정말 좋은 튜토리얼이 있습니다.

기본적으로 양식 데이터를 URL 인코딩 문자열로 전송하고 있음을 나타내도록 POST 요청의 헤더를 설정하고 동일한 형식으로 전송되도록 데이터를 설정해야합니다.

$http({
  method  : 'POST',
  url     : 'url',
  data    : $.param(xsrf),  // pass in data as strings
  headers : { 'Content-Type': 'application/x-www-form-urlencoded' }  // set the headers so angular passing info as form data (not request payload)
});

여기서는 jQuery의 param () 도우미 함수가 데이터를 문자열로 직렬화하는 데 사용되지만 jQuery를 사용하지 않는 경우 수동으로 수행 할 수도 있습니다.


1
링크에서 언급 된 실제 구현에 대한 세부 정보를 제공하지 않았기 때문에 중재자가 이전 답변을 삭제했습니다. 이 답변에 표시된 세부 정보를 제공하기 위해 이미 답변을 편집하고 있으므로 삭제하지 않고 추가 세부 정보를 제공하도록 먼저 요청한 경우 더 좋을 것입니다!
robinmitra

$.param마법을한다. jQuery + AngularJS 기반 앱을 보유한 사람에게 완벽한 솔루션입니다.
dashtinejad


4

Symfony2 사용자의 경우 :

이 작업을 위해 자바 스크립트에서 아무것도 변경하지 않으려면 symfony 앱에서 이러한 수정을 수행 할 수 있습니다.

Symfony \ Component \ HttpFoundation \ Request 클래스를 확장하는 클래스를 작성하십시오.

<?php

namespace Acme\Test\MyRequest;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;

class MyRequest extends Request{


/**
* Override and extend the createFromGlobals function.
* 
* 
*
* @return Request A new request
*
* @api
*/
public static function createFromGlobals()
{
  // Get what we would get from the parent
  $request = parent::createFromGlobals();

  // Add the handling for 'application/json' content type.
  if(0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/json')){

    // The json is in the content
    $cont = $request->getContent();

    $json = json_decode($cont);

    // ParameterBag must be an Array.
    if(is_object($json)) {
      $json = (array) $json;
  }
  $request->request = new ParameterBag($json);

}

return $request;

}

}

이제 app_dev.php의 클래스를 사용하십시오 (또는 사용하는 색인 ​​파일).

// web/app_dev.php

$kernel = new AppKernel('dev', true);
// $kernel->loadClassCache();
$request = ForumBundleRequest::createFromGlobals();

// use your class instead
// $request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

이것은 나에게 정말 유용했습니다. 새로운 createFromGlobals가 이제 완벽하게 작동합니다. 왜 공감대를 받았는지 모르겠지만 삭제했습니다.
Richard

3

Content-Type이 충분하지 않은 것으로 설정하면 보내기 전에 양식 데이터를 URL로 인코딩하십시오. $http.post(url, jQuery.param(data))


3

현재 AngularJS Google 그룹에서 찾은 다음 솔루션을 사용하고 있습니다.

$ http
.post ( '/ echo / json /', 'json ='+ encodeURIComponent (angular.toJson (data)), {
    헤더 : {
        '콘텐츠 유형': 'application / x-www-form-urlencoded; charset = UTF-8 '
    }
}). success (함수 (데이터) {
    $ scope.data = 데이터;
});

PHP를 사용하는 경우 Request::createFromGlobals()$ _POST가 자동으로로드되지 않으므로 Symfony 2 HTTP 구성 요소와 같은 것을 사용해야 합니다.


2

AngularJS는 http-request 헤더 내에서 다음과 같은 내용 유형을 수행하면서 올바르게 수행합니다.

Content-Type: application/json

나와 같은 PHP를 사용하거나 Symfony2를 사용하는 경우 http://silex.sensiolabs.org/doc/cookbook/json_request_body.html 과 같이 json 표준에 대한 서버 호환성을 간단히 확장 할 수 있습니다.

Symfony2 방식 (예 : DefaultController 내부) :

$request = $this->getRequest();
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
    $data = json_decode($request->getContent(), true);
    $request->request->replace(is_array($data) ? $data : array());
}
var_dump($request->request->all());

장점은 jQuery 매개 변수를 사용할 필요가 없으며 AngularJS를 기본적으로 사용하여 이러한 요청을 수행 할 수 있다는 것입니다.


2

완전한 답변 (각도 1.4 이후). 종속성 $ httpParamSerializer를 포함해야합니다.

var res = $resource(serverUrl + 'Token', { }, {
                save: { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
            });

            res.save({ }, $httpParamSerializer({ param1: 'sdsd', param2: 'sdsd' }), function (response) {

            }, function (error) { 

            });

1

앱 구성에서-

$httpProvider.defaults.transformRequest = function (data) {
        if (data === undefined)
            return data;
        var clonedData = $.extend(true, {}, data);
        for (var property in clonedData)
            if (property.substr(0, 1) == '$')
                delete clonedData[property];

        return $.param(clonedData);
    };

자원 요청으로-

 headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }

0

이것은 직접적인 대답이 아니라 약간 다른 디자인 방향입니다.

데이터를 양식으로 게시하지 말고 서버 측 오브젝트에 직접 맵핑 할 JSON 오브젝트로 또는 REST 스타일 경로 변수를 사용하십시오.

XSRF 키를 전달하려고하므로 귀하의 경우에 적합한 옵션이 없다는 것을 알고 있습니다. 이것을 경로 변수에 매핑하는 것은 끔찍한 디자인입니다.

http://www.someexample.com/xsrf/{xsrfKey}

때문에 자연 당신은 너무 다른 경로로 XSRF 키를 전달하려는 것 /login, /book-appointment등 당신은 엉망 예쁜 URL 싶지 않아

흥미롭게도 객체 필드로 추가하는 것도 적절하지 않습니다. 이제 서버에 전달하는 각 json 객체에서 필드를 추가해야하기 때문에

{
  appointmentId : 23,
  name : 'Joe Citizen',
  xsrf : '...'
}

확실히 도메인 측 객체와 직접적인 의미 론적 연관이없는 서버 측 클래스에 다른 필드를 추가하고 싶지 않습니다.

제 생각에는 xsrf 키를 전달하는 가장 좋은 방법은 HTTP 헤더를 이용하는 것입니다. 많은 xsrf 보호 서버 측 웹 프레임 워크 라이브러리가이를 지원합니다. 예를 들어 Java Spring에서는 X-CSRF-TOKENheader를 사용하여 전달할 수 있습니다 .

JS 객체를 UI 객체에 바인딩하는 Angular의 뛰어난 기능은 양식을 모두 게시하고 JSON을 게시하는 연습을 제거 할 수 있음을 의미합니다. JSON은 서버 측 객체로 쉽게 역 직렬화 될 수 있으며 맵, 배열, 중첩 된 객체 등과 같은 복잡한 데이터 구조를 지원할 수 있습니다.

폼 페이로드로 배열을 어떻게 게시합니까? 아마도 이런 식으로 :

shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday

아니면 이거:

shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday

둘 다 나쁜 디자인입니다 ..


0

이것은 내가 필요로하는 일입니다. 로그 인 데이터를 양식 데이터로 API에 보내야하고 Javascript Object (userData)가 자동으로 URL 인코딩 데이터로 변환됩니다.

        var deferred = $q.defer();
        $http({
            method: 'POST',
            url: apiserver + '/authenticate',
            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: userData
        }).success(function (response) {
            //logics
            deferred.resolve(response);
        }).error(function (err, status) {
           deferred.reject(err);
        });

이것은 내 Userdata가 어떻게

var userData = {
                grant_type: 'password',
                username: loginData.userName,
                password: loginData.password
            }

-1

$ http 객체를 생성 할 때 "data"대신 "params"속성을 사용하면됩니다.

$http({
   method: 'POST',
   url: serviceUrl + '/ClientUpdate',
   params: { LangUserId: userId, clientJSON: clients[i] },
})

위의 예에서 clients [i]는 JSON 객체입니다 (어쨌든 직렬화되지 않음). "data"대신 "params"를 사용하는 경우 angular는 $ httpParamSerializer를 사용하여 객체를 직렬화합니다. https://docs.angularjs.org/api/ng/service/ $ httpParamSerializer


2
Angular는 데이터 대신 params를 사용하여 요청 본문 대신 URL 매개 변수에 데이터를 배치합니다. 이것은 양식 게시물에서 예상되는 것이 아닙니다.
cmenning

-3

AngularJS $http서비스를 사용하고 해당 post방법을 사용 하거나 $http기능을 구성하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.