【问题标题】:How to prevent Django from writing to django_session table for certain URLs如何防止 Django 写入某些 URL 的 django_session 表
【发布时间】:2013-06-09 19:53:08
【问题描述】:

抱歉,如果我的问题与this one 非常相似,并且我尝试解决该问题的方法是 100% 基于该问题的答案,但我认为这稍微涉及更多,并且可能针对我的 Django 的一部分不完全明白。


我有一个用 Django 1.5 编写的 CMS 系统,其中有一些 API 可供两个无法像浏览器那样使用 cookie 的桌面应用程序访问。

我注意到,每当其中一个应用程序进行 API 调用(每 3 秒一次)时,都会在 django_session 表中添加一个新条目。仔细查看此表和代码,我可以看到特定 URL 的所有条目都被赋予相同的 session_data 值,但 session_key 不同。这可能是因为 Django 确定当这些调用之一是从无 cookie 应用程序进行时,request.session._session_keyNone

这样做的结果是每天在django_session 表中创建数千个条目,并且仅使用每日 cron 运行 ./manage clearsessions 不会将它们从该表中删除,从而使整个数据库变得非常大而没有明显的好处。请注意,我什至尝试set_expiry(1) 处理这些请求,但./manage clearsessions 仍然没有摆脱它们。

为了通过 Django 解决这个问题,我必须覆盖 3 个 Django 中间件,因为我正在使用 SessionMiddleware、AuthenticationMiddleware 和 MessageMiddleware:

from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.auth.middleware import AuthenticationMiddleware
from django.contrib.messages.middleware import MessageMiddleware

class MySessionMiddleware(SessionMiddleware):
    def process_request(self, request):
        if ignore_these_requests(request):
            return
        super(MySessionMiddleware, self).process_request(request)

    def process_response(self, request, response):
        if ignore_these_requests(request):
            return response
        return super(MySessionMiddleware, self).process_response(request, response)

class MyAuthenticationMiddleware(AuthenticationMiddleware):
    def process_request(self, request):
        if ignore_these_requests(request):
            return
        super(MyAuthenticationMiddleware, self).process_request(request)

class MyMessageMiddleware(MessageMiddleware):
    def process_request(self, request):
        if ignore_these_requests(request):
            return
        super(MyMessageMiddleware, self).process_request(request)

def ignore_these_requests(request):
    if request.POST and request.path.startswith('/api/url1/'):
            return True
    elif request.path.startswith('/api/url2/'):
        return True
    return False

虽然上述方法有效,但我无法停止思考,我可能已经让这变得更加复杂,而且这不是最有效的方法,因为每个请求都会进行 4 次额外检查。

在 Django 中有没有更好的方法来完成上述操作?任何建议将不胜感激。

【问题讨论】:

  • 其他解决方案包括更改会话引擎或会话生命周期。
  • 你能根据 HTTP 标头区分非会话感知客户端吗? (以用户代理为例)
  • @Thomas 我试图通过运行 set_expiry(1) 来更改会话生命周期,但由于某种原因,运行 ./manage clearsessions 并不能清除这些 - 不太清楚为什么
  • @gertvdijk 可以工作,但我不需要在类似于上述方法的 3 个中间件中创建 HTTP 标头检查吗?
  • @purplemass 是的。然而,一个肮脏的黑客将定义一个自定义的新中间件列出 SessionMiddleware,删除会话对象,例如del request.session。结合将settings.SESSION_SAVE_EVERY_REQUEST 留给False 这应该可以防止会话被写入数据库(尽管首先创建)。

标签: django session django-sessions


【解决方案1】:

Dirty hack:有条件地删除会话对象。

一种方法是包含一个中间件,根据请求丢弃会话对象。出于两个原因,这有点肮脏:

  • Session 对象首先创建,然后删除。 (低效)
  • 您所依赖的事实是 Session 对象此时尚未写入数据库。这可能会在未来的 Django 版本中发生变化(尽管可能性不大)。

创建custom middleware

class DiscardSessionForAPIMiddleware(object):

    def process_request(self, request):
        if request.path.startswith("/api/"): # Or any other condition
            del request.session

确保在您的MIDDLEWARE_CLASSES 元组django.contrib.sessions.middleware.SessionMiddleware 之后安装此settings.py

还要检查 settings.SESSION_SAVE_EVERY_REQUEST 是否设置为 False(默认值)。这使得它延迟写入数据库,直到数据被修改。


替代品(未经测试)

  • 在自定义中间件中使用process_view 而不是process_request,这样您就可以检查视图而不是请求路径。优点:条件检查更好。缺点:其他中间件可能已经对会话对象做了一些事情,然后这种方法就失败了。
  • 为您的 API 视图创建一个自定义装饰器(或共享基类),删除其中的会话对象。优势:执行此操作的责任在于视图,您可能最喜欢它的地方(视图提供 API)。缺点:同上,但在更晚的阶段删除会话对象。

【讨论】:

  • 非常感谢@gertvdijk。我使用了您建议的第一种方法,但更改了条件以检查 request.META['HTTP_COOKIE'],因为我们的桌面应用程序没有在他们的请求中设置它。另外,由于我使用的是 Django 的 AuthenticationMiddleware 和 MessageMiddleware,我在 MessageMiddleware 之后列出了这个自定义中间件。
  • 更新:request.META['HTTP_COOKIE'] 不是 CMS 用户第一次访问该站点时使用的正确检查,这是空的。最后我把它换成了request.META['HTTP_USER_AGENT']
【解决方案2】:

确保您的settings.SESSION_SAVE_EVERY_REQUEST 设置为False。这将大大有助于确保不会每次都保存会话。

另外,如果您有任何 ajax 请求发送到您的服务器,请确保该请求包含 cookie 信息,以便服务器不会认为每个请求属于不同的人。

【讨论】:

  • 感谢@Gevious - 我仔细检查了设置,发现settings.SESSION_SAVE_EVERY_REQUEST 确实设置为False。我还检查了 Ajax 请求:所有这些都来自 CMS,并且似乎保留了浏览器使用的会话,所以没有问题。
  • 您是否使用 curl 之类的方式向外部 Web 服务发出任何请求?还是您只是简单地接收来自浏览器的请求然后返回响应?
  • 有问题的请求都来自使用 C#/Unity 通过 HTTP 完成的桌面应用程序。 CMS 也有基于浏览器的标准用户,这些用户也使用这些 API
猜你喜欢
  • 1970-01-01
  • 2022-07-08
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 2011-04-15
相关资源
最近更新 更多