Таймер обратного отсчета с узлом экспресс. Не удается получить доступ к req.session

avatar
herman
7 апреля 2018 в 23:59
914
1
0

Я новичок в этом. Я пытаюсь настроить таймер, который запускается по указанному ниже маршруту. Это для корзины покупок, где корзина будет опорожнена по прошествии определенного времени.

setTimeout вызывает функцию с именем timer. По истечении времени я сталкиваюсь с ошибкой Не удается прочитать «сеанс» свойства неопределенного. Почему функция таймера не передает req.session? Он проходит нормально по всем моим маршрутам get.

app.js

app.use(function(req, res, next){
  res.locals.login = req.isAuthenticated();
  res.locals.session = req.session; //global variable for session.
  next();
});

Маршруты

router.get('/add/:id', function(req, res, next){
    var prodId = req.params.id;
    var cart = new Cart(req.session.cart ? req.session.cart : {})

    Prod.findById(prodId, function(err, prod){
        if (err) {
            return res.redirect('/');
        }
            cart.add(prod, prod.id);
            setTimeout(timer, 20000);  
            req.session.cart = cart;
            res.redirect('/show/' + prodId);
        } else {
            return res.redirect('/');
        }
    });
});

var timer = function(req, res){
    console.log(req.session.cart);
};
Источник
Marcos Casagrande
8 апреля 2018 в 00:03
0

вы не передаете req и res таймеру.. должно быть setTimeout(timer, 20000, req, res); Хотя я не буду рекомендовать это делать, это setTimeout укусит вас позже...

herman
8 апреля 2018 в 00:06
0

Ах хорошо. почему бы вам не порекомендовать этот метод?

Marcos Casagrande
8 апреля 2018 в 00:08
0

Вы сохраняете объект запроса и ответа после того, как запрос ушел. Если вы хотите очистить сессию через какое-то время, лучше добавьте время последней активности и проверьте в следующем запросе, если пользователь какое-то время был неактивен, уничтожьте сессию.

herman
8 апреля 2018 в 00:17
0

на самом деле, это оставляет меня с одной небольшой проблемой. причина, по которой я хотел использовать таймер, заключалась в том, что мне нужно вернуть предмет в инвентарь. если пользователь добавляет в корзину, но больше ничего не делает (например, больше не просит), то нет другого способа вернуться в инвентарь?

Marcos Casagrande
8 апреля 2018 в 00:19
0

Ну, есть несколько способов, корзина живет только в сеансе или у вас есть база данных? Если у вас есть корзина, сохраненная в БД, вы можете периодически удалять просроченные корзины из БД и возвращаться в инвентарь.

herman
8 апреля 2018 в 00:35
0

очень интересно. тележка живет в сеансе, но БД может иметь больше смысла. просто читаю о TTL в mongoDB сейчас. еще раз спасибо

Ответы (1)

avatar
jfriend00
8 апреля 2018 в 02:21
0

Я отвечу на ваш вопрос буквально (даже если вы можете выбрать другой тип решения вашей проблемы).

Есть несколько способов получить доступ к объекту сеанса в вашем таймере:

Создайте функцию-заглушку, которая пропускает сеанс:

Prod.findById(prodId, function(err, prod){
    if (err) {
        return res.redirect('/');
    }
        cart.add(prod, prod.id);
        setTimeout(function() {
           timer(req.session);
        }, 20000);  
        req.session.cart = cart;
        res.redirect('/show/' + prodId);
    } else {
        return res.redirect('/');
    }
});

function timer(session) {
    // do what you want to with the session
}

Используйте .bind(), чтобы передать сеанс обратному вызову:

Prod.findById(prodId, function(err, prod){
    if (err) {
        return res.redirect('/');
    }
        cart.add(prod, prod.id);
        setTimeout(timer.bind(null, req.session), 20000);  
        req.session.cart = cart;
        res.redirect('/show/' + prodId);
    } else {
        return res.redirect('/');
    }
});

function timer(session) {
    // do what you want to with the session
}

Добавить параметры к вызову setTimeout() (функция setTimeout):

Prod.findById(prodId, function(err, prod){
    if (err) {
        return res.redirect('/');
    }
        cart.add(prod, prod.id);
        setTimeout(timer, 20000, req.session);  
        req.session.cart = cart;
        res.redirect('/show/' + prodId);
    } else {
        return res.redirect('/');
    }
});

function timer(session) {
    // do what you want to with the session
}

Создать анонимный встроенный обратный вызов:

Prod.findById(prodId, function(err, prod){
    if (err) {
        return res.redirect('/');
    }
        cart.add(prod, prod.id);
        setTimeout(function() {
           // put your timer code here
           // it can directly access req.session here
           console.log(req.session); 
        }, 20000);  
        req.session.cart = cart;
        res.redirect('/show/' + prodId);
    } else {
        return res.redirect('/');
    }
});

P.S. Если вы используете таймер, вам, вероятно, следует сохранить идентификатор таймера в сеансе, и всякий раз, когда вы хотите установить новый таймер, вы вызываете clearTimeout() на предыдущем таймере, чтобы он не запускался, а затем назначаете новый идентификатор таймера сеансу.