2012-03-14 124 views
9

考虑这个Django的观点将得到有关当前用户的项目清单:在Ajax请求中处理会话超时的最佳方式是什么?

@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当未经身份验证的用户尝试访问视图时会做什么?它向settings.LOGIN_URL返回HttpResponseRedirect

考虑这段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装饰将检测该会话不再处于活动状态,并且将返回一个HttpResponseRedirect(settings.LOGIN_URL),这将导致success回调来获取HTML登录页面而不是JSON编码列表。

This is where it happens.
It's called by user_passes_test here.

什么是处理这个最好的方法是什么?

这里的一些事情我已经想到了:

1.success回调应检查响应,并看它是否得到一个登录页面,以任何方式(检查内容类型为HTML,检查内容等)。但是,这意味着我们必须包装都用AJAX回调的包装,像这样调用:

$.ajax({ 
     url: "/list_items/" + pageNumber + "/", 
     success: sessionExpiryCallbackWrapper(function(data) { 
      $("#list_container").html(formatData(data)) 
     }) 
    }); 

但这是丑陋的,和开发人员可能会忘记处处做到这一点。使用$.ajaxComplete来处理所有请求。

$.ajaxComplete(globalCompleteCallback); 
    $.ajax({ 
     success: successCallback, 
     complete: completeCallback 
    }); 

但是,这是调用顺序:

successCallback(); // success is called before complete 
    completeCallback(); 
    globalCompleteCallback(); // this is called after the local callback 

所以我们只能抓重定向,successCallback失败后,还可能与JS错误,由于它收到的无效数据。

3.如果login_required将在AJAX请求返回403:

if not user.is_authenticated(): 
     if request.is_ajax(): 
      # send 403 to ajax calls 
      return HttpResponse403("you are not logged in") 
     else: 
      # regular code path 
      return HttpResponseRedirect(settings.LOGIN_URL) 

login_required只是使用user_passes_test不这样做。

user_passes_test在那里有很多功能,所以重新实现它并不是一个好主意。

处理AJAX调用超时的最佳方式是什么?

+1

对不起,但我要对你全部哲学。会话超时的最初意图是防止服务器占用大量资源或不得不对每个请求执行昂贵的操作。我们现在拥有完成大部分工作的客户端框架。那么为什么短时间超时甚至需要? – 2012-03-14 01:30:46

+0

@DaveMethvin需要会话超时来缩小会话劫持的窗口,无论是a)在有线/无线上,还是b)物理上有人在AFK一点点后去别人的计算机。 – Prody 2012-03-14 08:53:11

+1

这个问题似乎很容易解决,只是客户端会话超时比服务器更短。如果是这种情况,那么客户端应该很少发出请求,发现自己在没有有效会话的服务器上。此外,这意味着你可以提出一个漂亮的客户端启动的“你的会话超时”消息。 – 2012-03-21 05:25:19

回答

5

我会通过让你的会话超时方法检查它是否被AJAX请求来处理它。如果是ajax,则返回401未授权(或403禁止或任何状态有意义)状态代码与一个空的json字符串。接下来,在你的javascript中,绑定一个全局的ajaxError处理程序,该处理程序检查该状态码并正确处理它。

+1

这就是我最终做的事情,但是我必须编写一个新的'login_required'装饰器来返回HttpResponse40 {1,3},如果request.is_ajax()else RedirectToLoginPage()'而不是只是重定向。 – Prody 2012-04-19 08:24:19

0

您可以使用像http://amplifyjs.com/可以让你写一个漂亮的包装为你的Ajax调用,然后使用其data mapping功能检查,如果用户正在做AJAX调用之前仍然登录。

这样,您可以拥有一个客户端计时器,该计时器将用户设置为注销状态并提供提示,以便在每次AJAX调用之前不需要执行登录检查。

或者,您可以使用自定义decoder,要求用户登录并在用户注销后重试AJAX调用。它需要存储所有的xhr数据和回调函数,直到用户登录。

相关问题