响应发送到客户端后,在Django中执行代码

时间:2010-11-30 12:04:13

标签: django http django-views httpresponse django-middleware

在我的Django应用程序中,我想跟踪响应是否已成功发送到客户端。我很清楚在像HTTP这样的无连接协议中没有“防水”方式来确保客户端已经接收(并显示)了响应,所以这不是关键任务功能,但我仍然希望在最新的可能时间。响应将不是HTML,因此无法从客户端回调(使用Javascript或IMG标签等)。

我能找到的“最新”钩子是在中间件列表的第一个位置添加一个实现process_response的自定义中间件,但据我了解,这是在构建实际响应并发送到客户端之前执行的。 Django中是否有任何钩子/事件在成功发送响应后执行代码?

3 个答案:

答案 0 :(得分:19)

我目前要使用的方法是使用HttpResponse的子类:

from django.template import loader
from django.http import HttpResponse

# use custom response class to override HttpResponse.close()
class LogSuccessResponse(HttpResponse):

    def close(self):
        super(LogSuccessResponse, self).close()
        # do whatever you want, this is the last codepoint in request handling
        if self.status_code == 200:
            print('HttpResponse successful: %s' % self.status_code)

# this would be the view definition
def logging_view(request):
    response = LogSuccessResponse('Hello World', mimetype='text/plain')
    return response

通过阅读Django代码,我非常确信HttpResponse.close()是将代码注入请求处理的最新点。我不确定与上述方法相比,此方法是否确实存在更好处理的错误情况,所以我现在暂时搁置这个问题。

我更喜欢这种方法的原因是lazerscience答案中提到的其他方法,它可以单独在视图中设置,不需要安装中间件。另一方面,使用request_finished信号将不允许我访问响应对象。

答案 1 :(得分:1)

我想在谈论中间件时,您正在考虑中间件的process_request方法,但是当返回HttpResponse对象时,还会调用process_response method。我想这将是你可以找到一个可以使用的钩子的最新时刻。

此外还有request_finished signal被解雇。

答案 2 :(得分:1)

如果您需要做很多事情,一个有用的技巧是拥有一个特殊的响应类,例如:

class ResponseThen(Response):
    def __init__(self, data, then_callback, **kwargs):
        super().__init__(data, **kwargs)
        self.then_callback = then_callback

    def close(self):
        super().close()
        self.then_callback()

def some_view(request):
    # ...code to run before response is returned to client

    def do_after():
        # ...code to run *after* response is returned to client

    return ResponseThen(some_data, do_after, status=status.HTTP_200_OK)

...如果您想要一种快速/灵活的“即发即忘”解决方案,而又无需费心集成适当的任务队列或从应用中分离出单独的微服务,则将为您提供帮助。