如何将数据作为表单数据而不是请求有效载荷发布?
在下面的代码中,AngularJS $http
方法调用URL,并将xsrf对象作为“Request Payload”提交(如Chromedebugging器networking选项卡中所述)。 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() {} });
以下行需要被添加到传递的$ http对象:
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
传递的数据应该转换为URL编码的string:
> $.param({fkey: "key"}) 'fkey=key'
所以你有这样的东西:
$http({ method: 'POST', url: url, data: $.param({fkey: "key"}), headers: {'Content-Type': 'application/x-www-form-urlencoded'} })
来自: https : //groups.google.com/forum/#!msg/angular/5nAedJ1LyO0/4Vj_72EZcDsJ
如果你不想在解决scheme中使用jQuery,你可以试试这个。 从这里抓取的解决schemehttps://stackoverflow.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 () {});
围绕这个问题持续的困惑激发我写一篇关于它的博客文章。 我在这篇文章中提出的解决scheme比当前评分最高的解决scheme更好,因为它不限制您为$ http服务调用设置数据对象。 即与我的解决scheme,你可以简单地继续传递实际的数据对象$ http.post()等,仍然达到预期的结果。
此外,评分最高的答案依赖于在$ .param()函数的页面中包含完整的jQuery,而我的解决scheme是jQuery不可知的,纯粹的AngularJS准备好了。
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
希望这可以帮助。
我采取了一些其他的答案,并做了一些更清洁,把这个.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("&"); }); }]);
从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";
要仅为当前post执行此操作,需要修改请求对象的headers
属性:
var req = { method: 'POST', url: 'http://example.com', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: $httpParamSerializer(formDataObj) }; $http(req);
您可以全局定义行为:
$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 });
作为一种解决方法,您可以简单地使接收POST的代码响应application / json数据。 对于PHP,我添加了下面的代码,允许我以POSTforms编码或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
这些答案看起来像疯狂的矫枉过正,有时候,简单就是更好:
$http.post(loginUrl, "userName=" + encodeURIComponent(email) + "&password=" + encodeURIComponent(password) + "&grant_type=password" ).success(function (data) { //...
你可以尝试下面的解决scheme
$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 */ });
有一个非常好的教程,通过这个和其他相关的东西 – 提交AJAX表单:AngularJS的方式 。
基本上,您需要设置POST请求的标头,以表明您正在将表单数据作为URL编码string发送,并将要发送的数据设置为相同的格式
$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()辅助函数在这里用于将数据序列化为string,但是如果不使用jQuery,也可以手动执行此操作。
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
为post创build一个适配器服务:
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) }) } })
对于Symfony2用户:
如果你不想改变你的JavaScript中的任何东西,你可以在你的symfony应用程序中做这些修改:
创build一个扩展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);
只要设置Content-Type是不够的,url发送前先对表单数据进行编码。 $http.post(url, jQuery.param(data))
我目前正在使用我在AngularJS谷歌组中find的以下解决scheme。
$ HTTP .post('/ echo / json /','json ='+ encodeURIComponent(angular.toJson(data)),{ 标题:{ 'Content-Type':'application / x-www-form-urlencoded; 字符集= UTF-8' } })。success(function(data){ $ scope.data = data; });
请注意,如果您使用PHP,则需要使用Symfony 2 HTTP组件的Request::createFromGlobals()
来读取它,因为$ _POST不会自动加载它。
AngularJS做的正确,因为它在http-request头文件中执行以下内容types:
Content-Type: application/json
如果你要像我一样使用php,甚至使用Symfony2,你可以简单地扩展你的服务器兼容性,像这里描述的json标准: http : //silex.sensiolabs.org/doc/cookbook/json_request_body.html
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原生的方式做这样的请求。
完整答案(自angular1.4)。 你需要包含de dependency $ 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) { });
在你的应用程序configuration –
$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' }
这不是一个直接的答案,而是一个略有不同的devise方向:
不要将数据作为表单发布,而是作为要直接映射到服务器端对象的JSON对象,或者使用REST风格的pathvariables
现在我知道这两个选项都不适合您的情况,因为您正在尝试传递XSRF密钥。 将其映射到像这样的pathvariables是一个可怕的devise:
http://www.someexample.com/xsrf/{xsrfKey}
因为从本质上讲,你也想把xsrf键传递给其他path, /login
, /book-appointment
等等,你不想搞乱你漂亮的URL
有趣的是,将它作为对象字段添加也是不合适的,因为现在在传递给服务器的每个json对象上都必须添加字段
{ appointmentId : 23, name : 'Joe Citizen', xsrf : '...' }
你当然不希望在你的服务器端类中添加另外一个与域对象没有直接语义关联的字段。
在我看来,传递你的xsrf键最好的方法是通过HTTP头。 许多xsrf保护服务器端web框架库支持这个。 例如在Java Spring中,您可以使用X-CSRF-TOKEN
标头来传递它 。
Angular将JS对象绑定到UI对象的优秀能力意味着我们可以摆脱发布表单的习惯,而是发布JSON。 JSON可以轻松地反序列化为服务器端对象,并支持复杂的数据结构,如地图,数组,嵌套对象等。
你如何张贴数组在表单有效载荷? 也许这样:
shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday
或这个:
shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday
两者都是不好的devise..
你必须改变的唯一方法是在创build$ http对象时使用属性“params”而不是“data”:
$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 $http
服务并使用其post
方法或configuration$http
函数。