Как создать запрос POST (включая токен CSRF) с использованием Django и AngularJS
Я пытаюсь создать запрос POST с помощью angular.js для этого представления Django.
class PostJSON4SlickGrid(View):
"""
REST POST Interface for SlickGrid to update workpackages
"""
def post(self, request, root_id, wp_id, **kwargs):
print "in PostJSON4SlickGrid"
print request.POST
return HttpResponse(status=200)
Поэтому я создал этот ресурс.
myModule.factory('gridData', function($resource) {
//define resource class
var root = {{ root.pk }};
return $resource('{% url getJSON4SlickGrid root.pk %}:wpID/', {wpID:'@id'},{
get: {method:'GET', params:{}, isArray:true},
update:{method:'POST'}
});
});
Вызов метода get в контроллере отлично работает. URL-адрес переводится на http://127.0.0.1:8000/pm/rest/tree/1/
.
function gridController($scope, gridData){
gridData.get(function(result) {
console.log(result);
$scope.treeData = result;
//broadcast that asynchronous xhr call finished
$scope.$broadcast('mySignal', {fake: 'Hello!'});
});
}
Пока я сталкиваюсь с проблемами, выполняющими метод update/POST.
item.$update();
URL-адрес преобразуется в http://127.0.0.1:8000/pm/rest/tree/1/345
, в котором отсутствует конечная косая черта. Это можно легко обойти, если вы не используете конечную косую черту в определении вашего URL.
url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),
вместо
url(r'^rest/tree/(?P<root_id>\d+)/(?P<wp_id>\d+)/$', PostJSON4SlickGrid.as_view(), name='postJSON4SlickGrid'),
Используя обходной путь без завершающей косой черты, я получаю код статуса 403 (Forbidden), который, вероятно, связан с тем, что я не передаю CSRF в запросе POST. Поэтому мой вопрос сводится к тому, как я могу передать токен CSRF в запрос POST, созданный angular?
Я знаю о этом подходе к передаче токена csrf через заголовки, но я ищу возможность добавить токен в тело отправить запрос, как предложено здесь. Возможно ли в angular добавить данные в тело запроса сообщения?
В качестве дополнительных показаний вы можете посмотреть эти обсуждения относительно ресурсов, удалить конечные косые черты и ресурсы ресурсов, которые в настоящее время имеют: disc1 и disc2.
В одном из обсуждений один из авторов рекомендовал в настоящее время не использовать ресурсы, но вместо этого используйте этот подход.
Ответы
Ответ 1
Вы не можете сделать такой вызов:
$http({
method: 'POST',
url: url,
data: xsrf,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
data
может быть любым, что вы хотите передать, а затем просто добавить &{{csrf_token}}
к этому.
В своем ресурсе params:{}
попробуйте добавить csrfmiddlewaretoken:{{csrf_token}}
внутри params
Edit:
Вы можете передать данные в тело запроса как
item.$update({csrfmiddlewaretoken:{{csrf_token}}})
а заголовки -
var csrf = '{{ csrf_token }}';
update:{method:'POST', headers: {'X-CSRFToken' : csrf }}
Это недокументированный issue
Ответ 2
Я знаю, что это больше 1 года, но если кто-то натыкается на ту же проблему, angular JS уже имеет механизм CIEF для получения cookie (версии AngularJS начиная с 1.1.5), и вам просто нужно сказать angular какое имя файла cookie использует django, а также HTTP-заголовок, который он должен использовать для связи с сервером.
Используйте для этого конфигурацию модуля:
var app = angular.module('yourApp');
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
Теперь каждый запрос будет иметь правильный токен CSRF django. По-моему, это гораздо правильнее, чем вручную помещать токен на каждый запрос, потому что он использует встроенные системы из обеих фреймворков (django и angularJS).
Ответ 3
В недавнем выпуске решения угловой версии решение не работает. Поэтому я попробовал следующее
angular.module('myApp').config(function ( $httpProvider) {
$httpProvider.interceptors.push('myHttpRequestInterceptor');
});
Ответ 4
var app = angular.module('angularFoo', ....
app.config(["$httpProvider", function(provider) {
provider.defaults.headers.common['X-CSRFToken'] = '<<csrftoken value from template or cookie>>';
}])
Ответ 5
Я использую это:
В представлении Django:
@csrf_protect
def index(request):
#Set cstf-token cookie for rendered template
return render_to_response('index.html', RequestContext(request))
В App.js:
(function(A) {
"use strict";
A.module('DesktopApplication', 'ngCookies' ]).config(function($interpolateProvider, $resourceProvider) {
//I use {$ and $} as Angular directives
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
//Without this Django not processed urls without trailing slash
$resourceProvider.defaults.stripTrailingSlashes = false;
}).run(function($http, $cookies) {
//Set csrf-kookie for every request
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
});
}(this.angular));
Для отправки правильного запроса вы должны преобразовать объект в param-форму:
$http.post('/items/add/', $.param({name: 'Foo'}));//Here $ is jQuery