【问题标题】:AngularJS - Any way for $http.post to send request parameters instead of JSON?AngularJS - $http.post 发送请求参数而不是 JSON 的任何方式?
【发布时间】:2012-08-24 18:50:54
【问题描述】:

我有一些旧代码通过jQuery's post method 发出 AJAX POST 请求,看起来像这样:

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

requestData 只是一个带有一些基本字符串属性的 javascript 对象。

我正在将我们的东西转移到使用 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发送body是这样的:

param1=value1&param2=value2&param3=value3

我遇到的端点是请求参数而不是 JSON。所以,我的问题是无论如何告诉$http.post 将javascript 对象作为请求参数而不是JSON 发送?是的,我知道我可以自己从对象构造字符串,但我想知道 Angular 是否为此提供了开箱即用的东西。

【问题讨论】:

    标签: javascript jquery post angularjs


    【解决方案1】:

    我认为params config 参数在这里不起作用,因为它将字符串添加到 url 而不是正文,但添加到 Infeligo 建议的内容是默认转换的全局覆盖示例(使用 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 的调用都会自动将正文转换为 jQuery $.post 调用使用的相同参数格式。

    请注意,您可能还希望在每次调用或全局设置 Content-Type 标头,如下所示:

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

    每次调用的示例非全局 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 参数函数。
    • 非全局每次调用方法对我来说效果很好,但是当尝试通过$httpProvider.defaults 全局设置时,它不起作用,有什么线索吗?
    • WRT 全局配置,我也有问题。当我尝试使用此处给出的 sn-p 执行此操作时,我收到错误 Cannot read property "jquery" of undefined. 如何解决此问题? PS。每次调用转换都有效。
    • @kshep92 发生的情况是 transformRequest 函数在没有数据的请求上被调用,因此“数据”未定义。我在“return $.param(data);”之前添加了一个守卫。将此作为第一行插入到 transformRequest 函数中:'if (data === undefined) return data;'请参阅我对答案所做的编辑。
    • 从 Angular 1.4 开始,您可以使用 $httpParamSerializer 代替 jQuery docs.angularjs.org/api/ng/service/$httpParamSerializer
    【解决方案2】:

    如果使用 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,并使用application/x-www-form-urlencoded; charset=utf-8 Content-Type 标头将其发送到/requesturl,正如端点上的POST请求通常所期望的那样。

    【讨论】:

      【解决方案3】:

      来自 AngularJS 文档:

      params – {Object.} – 字符串或对象的映射 会在 url 之后变成 ?key1=value1&key2=value2 。 如果 value 不是字符串,它将被 JSON 化。

      所以,提供字符串作为参数。如果您不希望那样,请使用转换。同样,来自文档:

      要在本地覆盖这些转换,请指定转换函数 作为配置的 transformRequest 和/或 transformResponse 属性 目的。要全局覆盖默认转换,请覆盖 $httpProvider.defaults.transformRequest 和 $httpProvider.defaults.transformResponse 的属性 $httpProvider。

      详情请参阅documentation

      【讨论】:

      • 我在文档中看到了参数,就像 Gloopy 提到的那样,我需要它在正文中,而不是在 URL 上。我想知道是否有一些选项或我缺少的东西来做参数而不是 JSON,但听起来我只需要使用 transformRequest 属性。
      【解决方案4】:

      使用jQuery的$.param函数序列化requestData中的JSON数据。

      简而言之,使用与您类似的代码:

      $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。

      【讨论】:

        【解决方案5】:

        请注意,从 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
        });
        

        【讨论】:

        • 这个答案很棒。它解决了来自 Angular 的 Post 的两个主要问题。标头必须正确设置,并且您必须序列化 json 数据。如果您不需要 IE8 支持,请使用 1.4+ 或更高版本。
        • 我刚刚实现了这个,它解决了我在发布时遇到的问题,但这也改变了补丁的工作方式,并且似乎破坏了我对 $http.patch() 的所有使用。
        【解决方案6】:

        这可能有点小题大做,但我避免了这个问题,并在服务器端将 json 转换为 PHP 的 POST 数组:

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

        【讨论】:

        • 我用过这种方法,但我讨厌它;我花了很长时间才弄清楚为什么我必须使用它。
        • 就像我说的 - 感觉很老套。像大多数 php ;)
        【解决方案7】:

        我在设置自定义 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 天的工作时间。谢谢!!!我仍在尝试弄清楚是否可以以某种方式拦截请求调用,以便可以为每个调用注入自定义标头。
        【解决方案8】:

        修改默认标题:

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

        然后使用JQuery的$.param方法:

        var payload = $.param({key: value});
        $http.post(targetURL, payload);
        

        【讨论】:

          【解决方案9】:
             .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 () {});
              }
            ]);
          

          【讨论】:

          • 根据我的最简单最简单的...可能还有很多其他方法
          【解决方案10】:

          快速调整 - 对于那些在 transformRequest 函数的全局配置方面遇到问题的人,这是我用来摆脱 Cannot read property 'jquery' of undefined 错误的 sn-p:

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

          【讨论】:

            【解决方案11】:

            您也可以在不更改服务器代码、更改 $http.post 调用中的标头并按常规方式使用 $_POST 的情况下解决此问题。在这里解释:http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

            【讨论】:

              【解决方案12】:

              我发现很多次有问题的行为。我从 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/angular 环境的当前阶段很常见。
              【解决方案13】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-03-31
                • 2016-02-23
                • 2014-04-16
                • 2015-02-26
                • 2017-05-12
                • 2013-10-15
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多