【问题标题】:Django, how to get the time until a cookie expiresDjango,如何获取cookie过期的时间
【发布时间】:2021-02-04 13:08:13
【问题描述】:

在标记为 dup 之前(我相信很多答案都不正确): 根据我的研究:

  • request.session.get_expiry_age 返回 cookie 的总寿命,而不是从现在到过期的时间。它总是返回相同的值,而不管剩下多少时间。
  • 类似地get_expiry_date 将总寿命添加到现在时间。调用时它总是增加。 因此,它们都没有帮助。

settings.SESSION_SAVE_EVERY_REQUEST 刷新每个请求的 cookie,这不是我想要实现的。

get_session_cookie_age() 仅返回 settings.SESSION_COOKIE_AGE 的值,如源代码所示:

def get_session_cookie_age(self):
    return settings.SESSION_COOKIE_AGE

我使用cached_db 会话后端。缓存部分无效,因为它必须每次都保存 cookie,因此 SESSION_SAVE_EVERY_REQUEST 不适用。我问这个问题的原因是因为我希望仅在剩余时间低于阈值时才刷新 cookie,因此会有一些歇斯底里(具有缓存和自动刷新的好处)。

由于get_expiry_age/get_expiry_date 的行为如上所述,我的代码无法正常工作:

from django.conf import settings
from django.utils.deprecation import MiddlewareMixin

class SessionExpiry(MiddlewareMixin):
    def process_request(self, request):
        """Automatically refresh a session expirary at a certain limit.

        If request.session age goes below settings.SESSION_REFRESH, then
        set the sessions expirary age to settings.SESSION_COOKIE_AGE. The
        session is not refreshed every time to have the caching benefits of
        the cached_db backend.
        """
        try:
            empty = request.session.is_empty()
        except AttributeError:
            return None
        if (empty or not getattr(settings, 'SESSION_REFRESH', None)):
            return None
        if request.session.get_expiry_age() < settings.SESSION_REFRESH:
            request.session.set_expiry(settings.SESSION_COOKIE_AGE)
        return None

【问题讨论】:

    标签: django session cookies session-cookies


    【解决方案1】:

    这是 Django 的一个领域,在设计和文档方面都令人困惑。弄清楚发生了什么的最简单方法是查看source code

    要获得所需的内容,您需要将自定义过期时间设置为 datetime。如果你使用秒数(包括默认的SESSION_COOKIE_AGE),它被解释为从现在开始的秒数;也就是说,从你问的时候开始。

    所以要设置过期时间,请使用:

    # Using timedelta will cause the session to save the expiration time as a datetime.
    request.session.set_expiry(timedelta(seconds=settings.SESSION_COOKIE_AGE))
    

    如果您这样做,对get_expiry_age() 的调用将返回当前日期时间与设置为到期的日期时间之间的实际差异。

    请务必注意 set_expiry() 文档中的警告:“请注意,datetimetimedelta 值只有在使用 PickleSerializer 时才能序列化。”

    【讨论】:

    • 你比我聪明,我确实看过源代码,但无法弄清楚参数,这对我来说似乎是循环依赖,传递到期数据以获取到期数据。非常感谢,太棒了!
    • 只需将timedelta(settings.SESSION_COOKIE_AGE) 更改为timedelta(seconds=settings.SESSION_COOKIE_AGE) 以便我可以将其标记为正确答案(否则timedelta 以天为单位设置)。 (编辑栏已满)
    • 虽然这在调试模式下有效,但当 django 尝试保存会话 (request.session.save()) 时,它会生成响应 Object of type datetime is not JSON serializable
    • 因为JSON不是pickle。
    • 我只是挥动白旗并使用SESSION_SAVE_EVERY_REQUEST,似乎不值得这么破解。
    【解决方案2】:

    从 Django 票来到这里。这是我想出的避免需要泡菜序列化程序和 SESSION_SAVE_EVERY_REQUEST 的方法。因此,我们可以使用普通时间戳代替datetime,由于set_expire 不支持,我们将添加另一个会话密钥来存储它。

    class RefreshSessionMiddleware(middleware.SessionMiddleware):
        def process_response(self, request, response):
            session = request.session
            if not (session.is_empty() or session.get_expire_at_browser_close()):
                expiry = session.get('_session_expire_at_ts')
                now_ts = int(time.time())
                cookie_lifetime = session.get_expiry_age()
                if expiry is None or now_ts + cookie_lifetime / 2 > expiry:
                    # This will set modified flag and update the cookie expiration time
                    session['_session_expire_at_ts'] = now_ts + cookie_lifetime
    
            return super().process_response(request, response)
    

    【讨论】:

    • 刚刚测试过,效果很好,干得好!!您似乎是唯一了解 django 到期如何工作的人。
    猜你喜欢
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    相关资源
    最近更新 更多