在下面的代码中,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() {}
});
需要在传递的 $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 添加的新服务,请参阅
仅使用 AngularJS 服务的 URL 编码变量
如果你不想在解决方案中使用 jQuery,你可以试试这个。从这里找到的解决方案 https://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 () {});
for
语句以使用 angular.forEach
。
obj[p]
是否不是 null 或 undefined。否则,您最终将发送“null”或“undefined”字符串作为值。
transformRequest: function(obj)
由于 obj 未定义,我们是否假设通过 xsrf?喜欢transformRequest: function(xsrf)
我采用了其他一些答案并做了一些更简洁的事情,将此 .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("&");
});
}]);
unshift()
,以便其他转换保持不受干扰。干得好。
从 AngularJS v1.4.0 开始,有一个内置的 $httpParamSerializer
服务,可以根据 docs page 中列出的规则将任何对象转换为 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";
要仅为当前帖子执行此操作,需要修改请求对象的 headers
属性:
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: $httpParamSerializer(formDataObj)
};
$http(req);
transformRequest: $httpParamSerializer, data: formDataObj
解决。感谢您的解决方案。
您可以全局定义行为:
$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,我添加了下面的代码,允许我以表单编码或 JSON 的形式发布到它。
//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) {
//...
Content-Type
并将其设置为 application/x-www-form-urlencoded
。
您可以尝试以下解决方案
$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 */
});
为 post 创建一个适配器服务:
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)
})
}
})
有一个非常好的教程,涵盖了这个和其他相关的东西 - Submitting AJAX Forms: The AngularJS Way。
基本上,您需要设置 POST 请求的标头以指示您将表单数据作为 URL 编码字符串发送,并将要发送的数据设置为相同的格式
$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,您也可以手动执行此操作。
$.param
施展魔法。谁拥有基于 jQuery+AngularJS 的应用程序的完美解决方案。
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 应用程序中进行以下修改:
创建一个扩展 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 google 组中使用以下解决方案我 found。
$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 组件的 Request::createFromGlobals()
之类的东西来阅读此内容,因为 $_POST 不会自动加载它。
AngularJS 做得对,因为它在 http-request 标头中执行以下内容类型:
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 的原生方式来执行此类请求。
完整答案(从角度 1.4 开始)。您需要包括 de 依赖 $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) {
});
在您的应用配置中 -
$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'
}
这不是一个直接的答案,而是一个稍微不同的设计方向:
不要将数据作为表单发布,而是作为 JSON 对象直接映射到服务器端对象,或者使用 REST 样式的路径变量
现在我知道这两个选项都不适合您的情况,因为您正在尝试传递 XSRF 密钥。将它映射到这样的路径变量是一个糟糕的设计:
http://www.someexample.com/xsrf/{xsrfKey}
因为从本质上讲,您也希望将 xsrf 密钥传递给其他路径,/login
、/book-appointment
等,并且您不想弄乱您漂亮的 URL
有趣的是,将其添加为对象字段也不合适,因为现在在您传递给服务器的每个 json 对象上,您都必须添加该字段
{
appointmentId : 23,
name : 'Joe Citizen',
xsrf : '...'
}
您当然不想在与域对象没有直接语义关联的服务器端类上添加另一个字段。
在我看来,传递 xsrf 密钥的最佳方式是通过 HTTP 标头。许多 xsrf 保护服务器端 Web 框架库都支持这一点。 For example in Java Spring, you can pass it using X-CSRF-TOKEN
header。
Angular 将 JS 对象绑定到 UI 对象的出色能力意味着我们可以摆脱将表单一起发布的做法,而改为发布 JSON。 JSON 可以很容易地反序列化为服务器端对象,并支持复杂的数据结构,如映射、数组、嵌套对象等。
您如何在表单有效负载中发布数组?也许是这样的:
shopLocation=downtown&daysOpen=Monday&daysOpen=Tuesday&daysOpen=Wednesday
或这个:
shopLocation=downtwon&daysOpen=Monday,Tuesday,Wednesday
两个设计都很差。。
这就是我正在做的事情,我需要将登录数据作为表单数据发送到 API,并且 Javascript 对象(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);
});
这就是我的用户数据
var userData = {
grant_type: 'password',
username: loginData.userName,
password: loginData.password
}
您唯一需要更改的是在创建 $http 对象时使用属性“params”而不是“data”:
$http({
method: 'POST',
url: serviceUrl + '/ClientUpdate',
params: { LangUserId: userId, clientJSON: clients[i] },
})
在上面的示例中,clients[i] 只是 JSON 对象(未以任何方式序列化)。如果您使用“参数”而不是“数据”,角度将使用 $httpParamSerializer 为您序列化对象:https://docs.angularjs.org/api/ng/service/$httpParamSerializer
使用 AngularJS $http
服务并使用它的 post
方法或配置 $http
函数。
不定期副业成功案例分享
var xsrf = $.param({fkey: "key"});
那太愚蠢了,为什么 Angular 不能在内部进行?headers: {Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}