【发布时间】:2011-10-19 07:23:34
【问题描述】:
使用 jQuery AJAX POST 调用 Django 以获取更新的 JSON 集。
在我的 JS 文件中包含 Django 应用程序的“django.middleware.csrf.CsrfViewMiddleware”和“django.middleware.csrf.CsrfResponseMiddleware”以及来自https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax 的代码。
$(document).ajaxSend(function(event, xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
会发生什么
- 清除浏览器 cookie 并加载页面。
- Django 以 403 禁止响应 AJAX POST 请求,然后使用 CSRF 设置一个 cookie。但是没有 JSON 数据。
- 再次触发 AJAX POST 请求
- Django 从 X-CSRFToken 标头接收 CSRF 令牌,并使用 JSON 集进行适当的响应。
产生 ajax 请求的 html 和 js 文件不是 django 产生的。 js 通过 jquery $.post() 与 django 交互。所以获取 csrf 令牌的唯一方法是在发送 post 数据之前调用 django。
在我看来,Django 文档中给出的 jQuery 函数解决方案还没有本地 cookie,并且在提交 POST 请求之前没有等待从服务器取回 cookie。但是当它与 403 一起使用时,它使用(现在本地存储的)cookie 进行后续尝试并且工作正常。
如何解决此问题,以便提前设置 cookie 并在 AJAX POST 请求中第一次使用该 cookie?我是否错误地认为 django csrf 可以严格从源自同一站点的 ajax 调用工作?
*此处与 CSRF 有关的其他问题根本不起作用,建议使用 ajax.Setup 而不是 ajaxSend,但根据此 https://code.djangoproject.com/ticket/15284?cversion=0&cnum_hist=6 ,这可能会导致其他 JS 出现问题,因此选择了 ajaxSend。*
【问题讨论】: