在ajax请求中处理会话超时的最佳方法是什么?

时间:2021-07-13 22:54:40

Consider this Django view which will get a list of items associated to the current user:

考虑这个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))

Obviously, it wants to use the login_required decorator, to restrict access to the view for logged-in users.

显然,它希望使用login_required装饰器来限制对登录用户的视图的访问。

What does login_required do when a non-authenticated user tries to access the view? It returns a HttpResponseRedirect toward settings.LOGIN_URL.

当未经身份验证的用户尝试访问视图时,login_required会执行什么操作?它向settings.LOGIN_URL返回一个HttpResponseRedirect。

Consider this JavaScript code, which calls the view:

考虑这个调用视图的JavaScript代码:

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

Suppose settings.SESSION_COOKIE_AGE = 60 seconds.

假设settings.SESSION_COOKIE_AGE = 60秒。

If a user goes to page 1, reads it for 61 seconds, then clicks on the button for page 2, Django's login_required decorator will detect that the session is no longer active, and will return a HttpResponseRedirect(settings.LOGIN_URL), which will cause the success callback to get a HTML login page instead of the JSON-encoded list.

如果用户转到第1页,将其读取61秒,然后单击第2页的按钮,Django的login_required装饰器将检测到会话不再处于活动状态,并将返回HttpResponseRedirect(settings.LOGIN_URL),这将导致获取HTML登录页面而不是JSON编码列表的成功回调。

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

这就是它发生的地方。它在这里由user_passes_test调用。

What's the best way to handle this?

处理这个问题的最佳方法是什么?

Here's a few things I've thought of:

这是我想到的一些事情:

1. The success callback should check the response, and see if it gets a login page, by whatever means (check if content-type is html, check contents, etc). But this means that we have to wrap all AJAX calls with a callback wrapper like so:

1.成功回调应检查响应,并通过任何方式查看它是否获得登录页面(检查内容类型是否为html,检查内容等)。但这意味着我们必须使用回调包装器包装所有AJAX调用,如下所示:

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

But this is ugly, and developers might forget to do this everywhere.

但这很丑陋,开发人员可能忘记在任何地方都这样做。

2. Use $.ajaxComplete to handle all requests.

2.使用$ .ajaxComplete来处理所有请求。

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

But this is the call order:

但这是电话订单:

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

So we only catch the redirect, after successCallback has failed, and possibly with JS errors due to the invalid data it received.

因此,在successCallback失败后,我们只捕获重定向,并且可能由于收到的数据无效而导致JS错误。

3. If login_required would return 403 on AJAX requests:

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)

But login_required just uses user_passes_test which doesn't do this.

但是login_required只使用不执行此操作的user_passes_test。

user_passes_test has a lot of functionality in there, so it's not such a good idea to reimplement it.

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

What's the best way to handle the timeouts for AJAX calls?

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

2 个解决方案

#1


5  

I would handle it by having your session timeout method check whether or not it is being requested with AJAX. If it is ajax, return a 401 not authorized(or 403 forbidden or whatever status makes sense) status code with an empty json string. Next, in your javascript, bind a global ajaxError handler that checks for that status code and handles it appropriately.

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

#2


1  

You could use something like http://amplifyjs.com/ that lets you write a nice wrapper for your AJAX calls and then use its data mapping feature to check if the user is still logged in before doing the AJAX call.

您可以使用http://amplifyjs.com/之类的东西,它可以让您为AJAX调用编写一个很好的包装器,然后使用它的数据映射功能来检查用户是否在进行AJAX调用之前仍然登录。

This way you can have a client-side timer that sets the user to logged-out status and provides a hint so the login check doesn't need to be done before every AJAX call.

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

Alternatively you can use a custom decoder which asks the user to log in and retries the AJAX call if the user was logged out. It would need to store all the xhr data and callbacks it gets called with until the user logs in.

或者,您可以使用自定义解码器,如果用户已注销,则会要求用户登录并重试AJAX调用。它需要存储它所调用的所有xhr数据和回调,直到用户登录为止。

#1


5  

I would handle it by having your session timeout method check whether or not it is being requested with AJAX. If it is ajax, return a 401 not authorized(or 403 forbidden or whatever status makes sense) status code with an empty json string. Next, in your javascript, bind a global ajaxError handler that checks for that status code and handles it appropriately.

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

#2


1  

You could use something like http://amplifyjs.com/ that lets you write a nice wrapper for your AJAX calls and then use its data mapping feature to check if the user is still logged in before doing the AJAX call.

您可以使用http://amplifyjs.com/之类的东西,它可以让您为AJAX调用编写一个很好的包装器,然后使用它的数据映射功能来检查用户是否在进行AJAX调用之前仍然登录。

This way you can have a client-side timer that sets the user to logged-out status and provides a hint so the login check doesn't need to be done before every AJAX call.

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

Alternatively you can use a custom decoder which asks the user to log in and retries the AJAX call if the user was logged out. It would need to store all the xhr data and callbacks it gets called with until the user logs in.

或者,您可以使用自定义解码器,如果用户已注销,则会要求用户登录并重试AJAX调用。它需要存储它所调用的所有xhr数据和回调,直到用户登录为止。