39

私のDjangoアプリケーションでは、応答がクライアントに正常に送信されたかどうかを追跡したいと思います。HTTPのようなコネクションレス型プロトコルには、クライアントが応答を受信(および表示)したことを確認する「防水」方法がないことをよく知っています。したがって、これはミッションクリティカルな機能ではありませんが、それでも、可能な限り最新の時間。応答はHTMLではないため、クライアントからのコールバック(JavascriptまたはIMGタグなどを使用)はできません。

私が見つけることができる「最新の」フックは、ミドルウェアリストの最初の位置にprocess_responseを実装するカスタムミドルウェアを追加することですが、私の理解では、これは実際の応答が構築されてクライアントに送信される前に実行されます。応答が正常に送信された後にコードを実行するためのフック/イベントはDjangoにありますか?

4

4 に答える 4

33

私が今行っているメソッドは、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シグナルを使用すると、応答オブジェクトにアクセスできなくなります。

于 2010-11-30T13:19:06.693 に答える
27

これを頻繁に行う必要がある場合、便利なトリックは次のような特別な応答クラスを用意することです。

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)

...適切なタスクキューを統合したり、アプリから別のマイクロサービスを分割したりすることなく、迅速でハッキーな「ファイアアンドフォーゲット」ソリューションが必要な場合に役立ちます。

于 2019-03-13T10:31:20.720 に答える
3

ミドルウェアについて話すとき、ミドルウェアのprocess_requestメソッドについて考えていると思いますが、オブジェクトが返されるときに呼び出されるprocess_responseメソッドもあります。HttpResponseそれが、使えるフックを見つけることができる最新の瞬間になると思います。

さらに、発砲されているrequest_finished信号もあります。

于 2010-11-30T12:09:54.150 に答える
0

Florian Ledermannのアイデアを少し変更しました...したがって、誰かがhttpresponse関数を通常どおりに使用できますが、関数を定義してその特定のhttpresponseにバインドすることができます。

old_response_close = HttpResponse.close
HttpResponse.func = None
def new_response_close(self):
    old_response_close(self)
    if self.func is not None:
        self.func()
HttpResponse.close = new_response_close

次の方法で使用できます。

def myview():
    def myfunc():
        print("stuff to do")
    resp = HttpResponse(status=200)
    resp.func = myfunc
    return resp

応答を送信し、その後に時間のかかるコードを実行する方法を探していました...しかし、バックグラウンド(おそらくセロリ)タスクを実行できる場合、これは役に立たなくなります。returnステートメントの前にバックグラウンドタスクを開始します。非同期である必要があるため、コードの実行が終了する前に応答が返されます。

- -編集 - -

私はついにセロリをawssqsで動作させるようになりました。基本的に「ハウツー」を投稿しました。この投稿で私の答えをチェックしてください: Celery Worker(Kombu.asynchronous.timer)を起動できません

于 2021-09-29T19:24:36.510 に答える