Каков наилучший способ обработки тайм-аутов сеанса в запросах ajax? - PullRequest
12 голосов
/ 14 марта 2012

Рассмотрим это представление 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 секунд.

Если aпользователь переходит на страницу 1, читает ее в течение 61 секунды, затем нажимает кнопку для страницы 2, декоратор Django login_required обнаружит, что сеанс больше не активен, и вернет HttpResponseRedirect(settings.LOGIN_URL),что вызовет success обратный вызов для получения страницы входа в HTML вместо закодированного в JSON списка.

Вот где это происходит.
Он вызывается user_passes_test здесь.

Какой лучший способ справиться с этим?

Вот несколько вещей, о которых я подумал:

1. successОбратный вызов должен проверить ответ и посмотреть, получит ли он страницу входа любым способом (проверить, является ли тип содержимого html, проверить содержимое и т. д.).Но это означает, что мы должны обернуть все вызовы AJAX оболочкой обратного вызова следующим образом:

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

Но это уродливо, и разработчики могут забыть делать это везде.

2.Используйте $.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 вернет 403 для запросов AJAX:

    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?

Ответы [ 2 ]

6 голосов
/ 14 марта 2012

Я бы справился с этим, попросив ваш метод тайм-аута сеанса проверить, запрашивается ли он с помощью AJAX. Если это ajax, верните код состояния 401 не авторизованный (или 403 запрещенный или какой-либо другой статус имеет смысл) с пустой строкой json. Затем в своем javascript свяжите глобальный обработчик ajaxError, который проверяет этот код состояния и обрабатывает его соответствующим образом.

1 голос
/ 22 марта 2012

Вы можете использовать что-то вроде http://amplifyjs.com/, что позволит вам написать красивую оболочку для ваших вызовов AJAX, а затем использовать ее отображение данных , чтобы проверить, вошел ли пользователь в систему, прежде чем выполнятьВызов AJAX.

Таким образом, у вас может быть клиентский таймер, который устанавливает для пользователя статус выхода из системы и дает подсказку, чтобы не нужно было проверять вход в систему перед каждым вызовом AJAX.

В качестве альтернативы вы можете использовать пользовательский декодер , который запрашивает у пользователя вход в систему и повторяет вызов AJAX, если пользователь вышел из системы.Необходимо будет хранить все данные xhr и обратные вызовы, с которыми он вызывается, пока пользователь не войдет в систему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...