考虑这个Django视图,它将获得与当前用户关联的项目列表:
@login_required
def list_items(request, page_number=0):
items = Paginator(request.user.items, 5).page(page_number).object_list
return HttpResponse(cjson.encode(items))
显然,它希望使用login_required
装饰器来限制对已登录用户的视图的访问。
当未经身份验证的用户尝试访问该视图时,login_required
会做什么?它向HttpResponseRedirect
返回settings.LOGIN_URL
。
考虑这个调用视图的JavaScript代码:
var getPage = function(pageNumber) {
$.ajax({
url: "/list_items/" + pageNumber + "/",
success: function(data) {
$("#list_container").html(formatData(data))
}
});
};
假设settings.SESSION_COOKIE_AGE = 60
秒。
如果用户转到第1页,将其读取61秒,然后单击第2页的按钮,Django的login_required
装饰器将检测到会话不再处于活动状态,并将返回{{1这将导致HttpResponseRedirect(settings.LOGIN_URL)
回调获取HTML登录页面而不是JSON编码列表。
This is where it happens.
It's called by user_passes_test
here.
处理此问题的最佳方法是什么?
以下是我想到的一些事情:
success
1.
回调应检查响应,并通过任何方式查看它是否获得登录页面(检查内容类型是否为html,检查内容等)。但这意味着我们必须使用回调包装器包装所有AJAX调用,如下所示:
success
但这很难看,开发人员可能忘记在任何地方都这样做。
$.ajax({
url: "/list_items/" + pageNumber + "/",
success: sessionExpiryCallbackWrapper(function(data) {
$("#list_container").html(formatData(data))
})
});
使用2.
来处理所有请求。
$.ajaxComplete
但这是电话订单:
$.ajaxComplete(globalCompleteCallback);
$.ajax({
success: successCallback,
complete: completeCallback
});
因此,在successCallback失败后,我们只捕获重定向,并且可能由于收到的数据无效而导致JS错误。
successCallback(); // success is called before complete
completeCallback();
globalCompleteCallback(); // this is called after the local callback
如果login_required
在AJAX请求中返回403:
3.
但是login_required
只使用user_passes_test
而不是这样做。
user_passes_test
有很多功能,所以重新实现它并不是一个好主意。
处理AJAX调用超时的最佳方法是什么?
答案 0 :(得分:6)
我会通过让你的会话超时方法检查它是否被AJAX请求来处理它。如果是ajax,则使用空的json字符串返回未授权的401
(或403禁止或任何有意义的状态)状态代码。接下来,在您的javascript中,绑定一个全局ajaxError
处理程序,该处理程序检查该状态代码并对其进行适当处理。
答案 1 :(得分:1)
您可以使用类似http://amplifyjs.com/的东西,让您为AJAX调用编写一个漂亮的包装器,然后使用其data mapping功能检查用户是否仍在登录之前进行AJAX调用。< / p>
通过这种方式,您可以拥有一个客户端计时器,将用户设置为注销状态并提供提示,以便在每次调用AJAX之前不需要进行登录检查。
或者,您可以使用自定义decoder,如果用户已注销,则会要求用户登录并重试AJAX调用。它需要存储它所调用的所有xhr数据和回调,直到用户登录。