How can I post data as form data instead of a request payload?
在下面的代码中,AngularJS
如何让AngularJS将xsrf作为表单数据而不是请求有效负载提交?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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() {} }); |
需要将以下行添加到传递的$ http对象中:
1 | headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'} |
并且传递的数据应转换为URL编码的字符串:
1 2 | > $.param({fkey:"key"}) 'fkey=key' |
所以你有类似的东西:
1 2 3 4 5 6 | $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
UPDATE
要使用AngularJS V1.4添加的新服务,请参阅
- 仅使用AngularJS服务的URL编码变量
如果你不想在解决方案中使用jQuery,你可以试试这个。从这里获得解决方案https://stackoverflow.com/a/1714899/1784301
1 2 3 4 5 6 7 8 9 10 11 12 | $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 () {}); |
围绕这个问题的持续困惑激发了我写一篇关于它的博客文章。我在这篇文章中提出的解决方案优于您当前的最高评级解决方案,因为它不会限制您为$ http服务调用参数化数据对象;即使用我的解决方案,您可以继续将实际数据对象传递给$ http.post()等,并仍然可以实现所需的结果。
此外,最受欢迎的答案依赖于在$ .param()函数的页面中包含完整的jQuery,而我的解决方案是jQuery不可知,纯粹的AngularJS就绪。
希望这可以帮助。
我拿了一些其他的答案并做了一些更清洁的东西,把这个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | .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("&"); }); }]); |
从AngularJS v1.4.0开始,有一个内置的
它可以像这样使用:
1 2 3 | $http.post('http://example.com', $httpParamSerializer(formDataObj)). success(function(data){/* response status 200-299 */}). error(function(data){/* response status 400-999 */}); |
请记住,对于正确的表单帖子,必须更改
1 | $http.defaults.headers.post["Content-Type"] ="application/x-www-form-urlencoded"; |
要仅对当前帖子执行此操作,需要修改request-object的
1 2 3 4 5 6 7 8 9 10 | var req = { method: 'POST', url: 'http://example.com', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: $httpParamSerializer(formDataObj) }; $http(req); |
您可以全局定义行为:
1 | $http.defaults.headers.post["Content-Type"] ="application/x-www-form-urlencoded"; |
所以你不必每次都重新定义它:
1 2 3 4 5 6 7 8 | $http.post("/handle/post", { foo:"FOO", bar:"BAR" }).success(function (data, status, headers, config) { // TODO }).error(function (data, status, headers, config) { // TODO }); |
作为一种解决方法,您可以简单地使接收POST的代码响应application / json数据。对于PHP,我添加了下面的代码,允许我以form-encoded或JSON对它进行POST。
1 2 3 4 5 6 7 | //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 |
这些答案看起来像疯狂的矫枉过正,有时,简单就是更好:
1 2 3 4 5 | $http.post(loginUrl,"userName=" + encodeURIComponent(email) + "&password=" + encodeURIComponent(password) + "&grant_type=password" ).success(function (data) { //... |
您可以尝试以下解决方案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $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 */ }); |
为帖子创建适配器服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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'} }) } }) |
在控制器或其他任何地方使用它:
1 2 3 4 5 6 7 8 9 10 11 12 | 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) }) } }) |
有一个非常好的教程可以解释这个和其他相关的东西 - 提交AJAX表单:AngularJS方式。
基本上,您需要设置POST请求的标头以指示您将表单数据作为URL编码的字符串发送,并将要发送的数据设置为相同的格式
1 2 3 4 5 6 | $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 2 3 4 5 6 7 8 9 10 | var fd = new FormData(); fd.append('file', file); $http.post(uploadUrl, fd, { transformRequest: angular.identity, headers: {'Content-Type': undefined} }) .success(function(){ }) .error(function(){ }); |
请结账!
https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
对于Symfony2用户:
如果您不想更改javascript中的任何内容以使其工作,您可以在symfony app中进行以下修改:
创建一个扩展Symfony Component HttpFoundation request类的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php namespace Acme\Test\MyRequest; use Symfony\Component\HttpFoundation equest; 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(或您使用的任何索引文件)中使用您的类
1 2 3 4 5 6 7 8 9 10 11 | // 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); |
我目前正在使用我在AngularJS谷歌小组中找到的以下解决方案。
1 2 3 4 5 6 7 8 | $http .post('/echo/json/', 'json=' + encodeURIComponent(angular.toJson(data)), { headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }).success(function(data) { $scope.data = data; }); |
请注意,如果您使用的是PHP,则需要使用类似Symfony 2 HTTP组件的
仅设置Content-Type是不够的,url在发送之前对表单数据进行编码。
AngularJS正在执行它,因为它在http-request标头内执行以下内容类型:
1 | Content-Type: application/json |
如果您使用像我这样的PHP,或者甚至使用Symfony2,您可以简单地扩展您的json标准的服务器兼容性,如下所述:http://silex.sensiolabs.org/doc/cookbook/json_request_body.html
Symfony2方式(例如在DefaultController中):
1 2 3 4 5 6 | $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 param,并且您可以使用AngularJS以其本机方式执行此类请求。
完整答案(自角度1.4)。您需要包含de dependency $ httpParamSerializer
1 2 3 4 5 6 7 8 9 | 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 2 3 4 5 6 7 8 9 10 | $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); }; |
根据您的资源请求 -
1 2 3 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' } |
这就是我正在为我的需要做的事情,我需要将登录数据作为表单数据发送到API,并且Javascript对象(userData)自动转换为URL编码数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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的方式
1 2 3 4 5 | var userData = { grant_type: 'password', username: loginData.userName, password: loginData.password } |
这不是一个直接的答案,而是一个略有不同的设计方向:
不要将数据作为表单发布,而是作为JSON对象直接映射到服务器端对象,或者使用REST样式的路径变量
现在我知道在您尝试传递XSRF密钥时,这两种选项都不适用于您的情况。将它映射到这样的路径变量是一个可怕的设计:
1 | http://www.someexample.com/xsrf/{xsrfKey} |
因为本质上你也希望将xsrf键传递给其他路径,
有趣的是,将它添加为对象字段也不合适,因为现在每个json对象都传递给服务器,你必须添加字段
1 2 3 4 5 | { appointmentId : 23, name : 'Joe Citizen', xsrf : '...' } |
您当然不希望在服务器端类上添加另一个字段,该字段与域对象没有直接的语义关联。
在我看来,传递xsrf密钥的最佳方法是通过HTTP头。许多xsrf保护服务器端Web框架库都支持此功能。例如,在Java Spring中,您可以使用
Angular将JS对象绑定到UI对象的出色能力意味着我们可以摆脱一起发布表单的做法,而不是发布JSON。 JSON可以轻松地反序列化为服务器端对象,并支持复杂的数据结构,如地图,数组,嵌套对象等。
如何在表单有效负载中发布数组?也许是这样的:
1 | shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday |
或这个:
1 | shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday |
两者都是糟糕的设计..
在创建$ http对象时,唯一需要更改的是使用属性"params"而不是"data":
1 2 3 4 5 | $http({ method: 'POST', url: serviceUrl + '/ClientUpdate', params: { LangUserId: userId, clientJSON: clients[i] }, }) |
在上面的示例中,clients [i]只是JSON对象(不以任何方式序列化)。如果使用"params"而不是"data",angular将使用$ httpParamSerializer为您序列化对象:https://docs.angularjs.org/api/ng/service/$httpParamSerializer
使用AngularJS