响应发送到客户端后在 Django 中执行代码
在我的 Django 应用程序中,我想跟踪响应是否已成功发送到客户端。我很清楚,像 HTTP 这样的无连接协议中没有“无懈可击”的方式来确保客户端已收到(并显示)响应,因此这不会是关键任务功能,但我仍然想在最晚可能的时间。响应不是 HTML,因此客户端的任何回调(使用 Javascript 或 IMG 标签等)都是不可能的。
我能找到的“最新”钩子是在中间件列表的第一个位置添加一个实现 process_response 的自定义中间件,但据我了解,这是在构建实际响应并将其发送到客户端之前执行的。 Django 中是否有任何钩子/事件可以在响应发送成功后执行代码?
In my Django application I want to keep track of whether a response has been sent to the client successfully. I am well aware that there is no "watertight" way in a connectionless protocol like HTTP to ensure the client has received (and displayed) a response, so this will not be mission-critical functionality, but still I want to do this at the latest possible time. The response will not be HTML so any callbacks from the client (using Javascript or IMG tags etc.) are not possible.
The "latest" hook I can find would be adding a custom middleware implementing process_response at the first position of the middleware list, but to my understanding this is executed before the actual response is constructed and sent to the client. Are there any hooks/events in Django to execute code after the response has been sent successfully?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我现在要使用的方法使用 HttpResponse 的子类:
通过阅读 Django 代码,我非常确信 HttpResponse.close() 是将代码注入请求处理的最新点。我不确定是否真的存在通过这种方法比上面提到的方法处理得更好的错误情况,所以我暂时保留这个问题。
与 lazerscience 的答案中提到的其他方法相比,我更喜欢这种方法的原因是它可以单独在视图中设置,并且不需要安装中间件。另一方面,使用 request_finished 信号不允许我访问响应对象。
The method I am going for at the moment uses a subclass of HttpResponse:
By reading the Django code I am very much convinced that HttpResponse.close() is the latest point to inject code into the request handling. I am not sure if there really are error cases that are handled better by this method compared to the ones mentioned above, so I am leaving the question open for now.
The reasons I prefer this approach to the others mentioned in lazerscience's answer are that it can be set up in the view alone and does not require middleware to be installed. Using the request_finished signal, on the other hand, wouldn't allow me to access the response object.
如果您需要经常这样做,一个有用的技巧是拥有一个特殊的响应类,例如:
...如果您想要一个快速/黑客的“即发即忘”解决方案,而无需费心集成适当的任务队列或拆分任务队列,则可以提供帮助将微服务与您的应用程序分开。
If you need to do this a lot, a useful trick is to have a special response class like:
...helps if you want a quick/hacky "fire and forget" solution without bothering to integrate a proper task queue or split off a separate microservice from your app.
我想在谈论中间件时,您正在考虑中间件的 process_request 方法,但还有一个
process_response
方法,在返回HttpResponse
对象时调用。我想这将是您可以找到可以使用的钩子的最新时刻。此外,还有一个
request_finished
信号被发射。I suppose when talking about middleware you are thinking about the middleware's
process_request
method, but there's also aprocess_response
method that is called when theHttpResponse
object is returned. I guess that will be the latest moment where you can find a hook that you can use.Furthermore there's also a
request_finished
signal being fired.我发现了一个肮脏的技巧,通过访问 HttpResponse 中的受保护成员来做到这一点。
它适用于 Django 3.0.6 ,检查 HttpResponse 原型中的“close”函数。
I found a filthy trick to do this by accessing a protected member in HttpResponse.
It works in Django 3.0.6 , check the "close" function in the prototype of HttpResponse.
我稍微修改了 Florian Ledermann 的想法...所以有人可以正常使用 httpresponse 函数,但允许他们定义一个函数并将其绑定到特定的 httpresponse。
它可以通过以下方式使用:
我正在寻找一种发送响应的方法,然后执行一些耗时的代码...但是如果我可以运行一个后台(很可能是芹菜)任务,那么它将呈现这个对我来说没用。我将在返回语句之前启动后台任务。它应该是异步的,因此响应将在代码执行完成之前返回。
---编辑---
我终于让 celery 与 aws sqs 一起工作。我基本上发布了“如何做”。看看我在这篇文章中的回答:
无法启动 Celery Worker (Kombu.asynchronous.timer)
I modified Florian Ledermann's idea a little bit... So someone can just use the httpresponse function normally, but allows for them to define a function and bind it to that specific httpresponse.
It can be used via:
I was looking for a way to send a response, then execute some time consuming code after... but if I can get a background (most likely a celery) task to run, then it will have rendered this useless to me. I will just kick off the background task before the return statement. It should be asynchronous, so the response will be returned before the code is finished executing.
---EDIT---
I finally got celery to work with aws sqs. I basically posted a "how to". Check out my answer on this post:
Cannot start Celery Worker (Kombu.asynchronous.timer)