Gunicorn: Alter Fehler reproduziert: Das Objekt „Response“ hat kein Attribut „status_code“ in wsgi.py mit Websockets

Erstellt am 9. Aug. 2018  ·  33Kommentare  ·  Quelle: benoitc/gunicorn

Genau wie diese alte Ausgabe 1210 sagte, protokolliert Gunicorn einen Fehler, wenn der Client die Verbindung trennt, und meine Umgebung ist:

  • Debian GNU/Linux 7.8

  • nginx

  • Python3.4

  • gunicorn(19.8.1) (mit einem oder mehreren Arbeitern)

  • Flask-SocketIO, der Client gibt den Websocket-Transport an

Alles funktioniert gut, einschließlich Clients, außer diesem Fehlerprotokoll, zwei Cloud-unabhängigen Produktionsinstanzen, die beide dauerhaft protokollieren, aber ich kann es nicht auf meinem Entwicklungscomputer reproduzieren, der ein Mac ist.

Vielen Dank für Ihre Hilfe.

Fehlerbehandlungsanfrage /socket.io/?EIO=3&transport=websocket
Traceback (letzter Aufruf zuletzt):
Datei „/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/workers/async.py“, Zeile 56, im Handle
self.handle_request(listener_name, req, client, addr)
Datei „/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/workers/async.py“, Zeile 116, in handle_request
bzw. schließen()
Datei "/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/http/wsgi.py", Zeile 409, in der Nähe
self.send_headers()
Datei „/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/http/wsgi.py“, Zeile 325, in send_headers
tosend = self.default_headers()
Datei „/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/http/wsgi.py“, Zeile 306, in default_headers
elif self.should_close():
Datei „/opt/apps/lms/virtualenv/lib/python3.4/site-packages/gunicorn/http/wsgi.py“, Zeile 229, in should_close
wenn self.status_code < 200 oder self.status_code in (204, 304):
AttributeError: 'Response'-Objekt hat kein Attribut 'status_code'

Feedback Requested unconfirmed ThirdPartFlask

Hilfreichster Kommentar

Bump @benoitc

Alle 33 Kommentare

Haben Sie ein einfaches Beispiel, um es zu reproduzieren? Bitte versuchen Sie es auch mit dem neuesten Master, wenn möglich.

Zuvor habe ich es mehrmals in meiner lokalen Entwicklungsumgebung versucht, die derselbe Anwendungscode wie in der Produktionsumgebung ist, aber ich kann es nicht reproduzieren.

Und ich habe das Versionsprotokoll von Version 19.9.0 überprüft, nichts Verwandtes gefunden, ich werde es behalten
Wenn Sie sich dieses Fehlerprotokoll ansehen, wenn Sie etwas Neues finden, würde ich es hier posten.

Auch ich habe dieses Problem, insbesondere wenn ich meine gesamte Verbindung vom Client zum Websocket-Protokoll erzwinge. Meine Einstellungen sind die gleichen wie bei BoWuGit. Wenn das Polling-Protokoll vor dem Upgrade zugelassen wird, wird dies nicht angezeigt, aber ein weiterer Fehler:
`
[FEHLER] Fehlerbehandlung der Anfrage /socket.io/?EIO=3&transport=polling&t=MPRHUoV&sid=cd64be7c940e474d8728b114c3fb9bbe

Traceback (letzter Aufruf zuletzt):
Datei "/usr/local/lib/python3.6/site-packages/gunicorn/workers/async.py", Zeile 56, im Handle
self.handle_request(listener_name, req, client, addr)

Datei „/usr/local/lib/python3.6/site-packages/gunicorn/workers/async.py“, Zeile 107, in handle_request
respiter = self.wsgi(environ, resp.start_response)

Datei "/usr/local/lib/python3.6/site-packages/flask/app.py", Zeile 1994, in __call__
return self.wsgi_app(environ, start_response)

Datei "/usr/local/lib/python3.6/site-packages/flask_socketio/__init__.py", Zeile 43, in __call__
start_response)

Datei „/usr/local/lib/python3.6/site-packages/engineio/middleware.
py", Zeile 47, in __call__
return self.engineio_app.handle_request(environ, start_response)

Datei „/usr/local/lib/python3.6/site-packages/socketio/server.py“, Zeile 360, in handle_request
return self.eio.handle_request(environ, start_response)

Datei „/usr/local/lib/python3.6/site-packages/engineio/server.py“, Zeile 279, in handle_request
socket = self._get_socket(sid)

Datei „/usr/local/lib/python3.6/site-packages/engineio/server.py“, Zeile 439, in _get_socket
Raise KeyError('Sitzung wurde getrennt')
`
Aber ich vermute, dass es etwas miteinander zu tun haben könnte, da ich die Verbindung zu Websocket erzwinge, wurde dieser Fehler nicht wieder gesehen.

Dieses Problem tritt auch bei Gunicorn 19.9.0 und Flask-socketIO 3.0.2 auf, wenn Eventlet 0.24.1 verwendet wird

AttributeError: 'Response'-Objekt hat kein Attribut 'status_code'

Dieses Problem tritt auch bei den folgenden Anforderungen auf:

Flask==1.0.2
gunicorn==19.5.0
python-socketio==2.0.0
eventlet==0.24.1

Fehlermeldung beim Schließen des Webbrowsers mit offener Socket-Verbindung:

 Error handling request /socket.io/?EIO=3&transport=websocket&sid=d43ec0ae0bb946debc51f1ca2e5b8a94
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/gunicorn/workers/async.py", line 52, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/usr/lib/python2.7/dist-packages/gunicorn/workers/async.py", line 114, in handle_request
    resp.close()
  File "/usr/lib/python2.7/dist-packages/gunicorn/http/wsgi.py", line 403, in close
    self.send_headers()
  File "/usr/lib/python2.7/dist-packages/gunicorn/http/wsgi.py", line 319, in send_headers
    tosend = self.default_headers()
  File "/usr/lib/python2.7/dist-packages/gunicorn/http/wsgi.py", line 300, in default_headers
    elif self.should_close():
  File "/usr/lib/python2.7/dist-packages/gunicorn/http/wsgi.py", line 233, in should_close
    if self.status_code < 200 or self.status_code in (204, 304):
AttributeError: 'Response' object has no attribute 'status_code'

Es sieht so aus, als ob dieses Problem in der neuesten Version von python-engineio behoben wurde.

Habe mit der neuesten Version von python-engineio (2.3.2) getestet, funktioniert immer noch nicht.

Irgendwelche Neuigkeiten zu diesem Thema? Ich bekomme den gleichen Fehler, wenn ich Sentry-Python verwende

Ich habe das gleiche Problem

Ereignis: 0.25.1
Kolben-Sockel: 4.2.1
gunicorn: 19.9.0

image

image

wie kann man es reproduzieren? Können Sie ein einfaches Beispiel geben?

Ich bin mir auch nicht sicher, wie ich es reproduzieren soll, aber es passiert OFT, wenn ich eine Seite in meiner Gunicorn-App aktualisiere

Tritt auf das gleiche Problem, und meine Umgebung ist die gleiche wie @eazow, während gunicorn == 20.0.4.
Es scheint, dass das Problem aufgetreten ist, nachdem ich Sentry für die Fehlerverfolgung installiert habe.
Die Ausgaben können reproduziert werden

  1. Seite aktualisieren (keine neue Seite öffnen)
  2. Schließen der Seite

Interessanterweise wird das Öffnen einer neuen Seite das Problem nicht hervorrufen. Nicht sicher warum. Danke!

Ich habe das gleiche Problem wie @cowbonlin . Dieselbe Gunicorn-Version auch.

Nach der Installation von Sentry erhalten wir verrückte Mengen dieses Fehlers. Obwohl es mir schwer fällt zu sagen, ob dies immer passiert ist oder nicht - da wir Fehler vor dem Wachposten nicht nachverfolgt haben.

Auch wenn es die eigentliche Funktionalität unseres Servers nicht zu beeinflussen scheint, ist dies nur eine Menge Spam.

Wir erleben das gleiche. Sentry installiert, aber deaktiviert. Irgendwelche Ideen?

Gleiches Problem mit installiertem Sentry.

Haben Sie ein Beispiel, das es ohne Wachposten reproduziert (deaktiviert oder nicht)?

Außerdem drücke ich anstelle eines Namespace manuell auf /api.

Außerdem drücke ich anstelle eines Namespace manuell auf /api.

was bedeutet das ? Ist dieser Wachposten verwandt?

Außerdem drücke ich anstelle eines Namespace manuell auf /api.

was bedeutet das ? Ist dieser Wachposten verwandt?

Nein, dies bezieht sich auf socket.io-Namespaces. Ich habe versucht, sie zu entfernen, und selbst nachdem ich sie entfernt habe, erhalte ich den Fehler. Ich erhalte jedoch diesen anderen Fehler auf dem lokalen Computer ohne Gunicorn oder Nginx, der möglicherweise damit zusammenhängt.

Das sind meine Anforderungen:

sentry_sdk == 0.14.3
Flask_SocketIO == 4.2.1
eventlet == 0.25.1

Dies ist mein Flask-Socketio-Code auf der Serverseite:

socketio = SocketIO(engineio_logger=True, logger=True, debug=True, cors_allowed_origins="*", path='/socket.io')
...
socketio.init_app(app, async_mode="eventlet")

Und das ist mein React-Socket-IO-Code auf der Client-Seite:

          this.socket = io.connect(`http://localhost:5000?info=${someInfo}`, {
            transports: ['websocket', 'polling'] // an attempt to keep polling as a fallback but start on websockets
          });

Lassen Sie mich wissen, ob das hilft. Unter Ubuntu sieht der Fehler wie oben aus, und lokal unter Windows sieht er so aus:
```Traceback (letzter Aufruf zuletzt):
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py“, Zeile 599, in handle_one_response
schreibe(b'')
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py", Zeile 491, in write
raise AssertionError("write() before start_response()")
AssertionError: write() vor start_response()

Während der Behandlung der obigen Ausnahme ist eine weitere Ausnahme aufgetreten:

Traceback (letzter Aufruf zuletzt):
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py", Zeile 357, in __init__
self.handle()
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py“, Zeile 390, im Handle
self.handle_one_request()
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py“, Zeile 466, in handle_one_request
self.handle_one_response()
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py“, Zeile 609, in handle_one_response
schreiben (err_body)
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py", Zeile 538, in write
wfile.flush()
Datei "C:\ProgramData\Anaconda3\lib\socket.py", Zeile 607, in write
sende self._sock.send(b) zurück
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\greenio\base.py", Zeile 397, in send
return self._send_loop(self.fd.send, Daten, Flags)
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\greenio\base.py", Zeile 384, in _send_loop
return send_method(data, *args)
ConnectionAbortedError: [WinError 10053] Eine hergestellte Verbindung wurde von der Software auf Ihrem Hostcomputer abgebrochen

Während der Behandlung der obigen Ausnahme ist eine weitere Ausnahme aufgetreten:

Traceback (letzter Aufruf zuletzt):
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\hubs\hub.py“, Zeile 461, in fire_timers
Timer()
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\hubs\timer.py", Zeile 59, in __call__
cb( args, * kw)
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\semaphore.py", Zeile 147, in _do_acquire
Kellner.switch()
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\greenthread.py", Zeile 221, in main
result = function( args, * kwargs)
Datei „C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py“, Zeile 818, in process_request
proto.__init__(conn_state, selbst)
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py", Zeile 359, in __init__
self.finish()
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\wsgi.py", Zeile 732, fertig
BaseHTTPServer.BaseHTTPRequestHandler.finish (selbst)
Datei "C:\ProgramData\Anaconda3\lib\socketserver.py", Zeile 784, fertig
self.wfile.close()
Datei "C:\ProgramData\Anaconda3\lib\socket.py", Zeile 607, in write
sende self._sock.send(b) zurück
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\greenio\base.py", Zeile 397, in send
return self._send_loop(self.fd.send, Daten, Flags)
Datei "C:\ProgramData\Anaconda3\lib\site-packages\eventlet\greenio\base.py", Zeile 384, in _send_loop
return send_method(data, *args)
ConnectionAbortedError: [WinError 10053] Eine hergestellte Verbindung wurde von der Software auf Ihrem Host-Rechner abgebrochen

Kann bestätigen, dass dieser Fehler verschwindet, wenn Sentry vollständig deaktiviert ist. Wäre großartig, wenn Gunicorn robust genug wäre, um damit fertig zu werden.

Bump @benoitc

Kann bestätigen, dass dieser Fehler verschwindet, wenn Sentry vollständig deaktiviert ist. Wäre großartig, wenn Gunicorn robust genug wäre, um damit fertig zu werden.

Ich habe festgestellt, dass das Deaktivieren von FlaskIntegration des Sentry den Fehler ebenfalls verschwinden lässt.

Ähnliches Verhalten sehen. Die Verwendung von New Relic in der Produktion verursacht diesen Fehler mit Flask-Socketio. In der Entwicklung muss die Tool-Debugger-Middleware geladen werden, bevor Flask-Socketio initialisiert wird (sie wird also nicht auf die wsgi-App von engineio angewendet). Das Problem ist, dass die Produktion dort ist, wo ich wirklich nicht möchte, dass die Fehler auslösen.

Die Antwort in post_request von gunicorn config kann nicht ersetzt werden, aber ich habe versucht, einen Statuscode auf resp.status_code zu erzwingen. Es hat aber nicht gedauert.

Dieser Fehler ist reproduzierbar, wenn FlaskIntegration von Sentry zusammen mit Gunicorn und Flask-SocketIO verwendet wird. Ist eine baldige Lösung möglich?

@Canicio , wir dachten, wir sollten das versuchen, um den Fehler zu beseitigen, und selbst nach dem Deaktivieren der Integration bleibt der Fehler bestehen.

Hat jemand gemeinsam nutzbaren Code/ein minimales Beispiel für @benoitc , um davon auszugehen?

Sicher:

import sentry_sdk
from flask import Flask
from flask_socketio import SocketIO
from sentry_sdk.integrations.flask import FlaskIntegration

sentry_sdk.init(
    dsn="https://[email protected]/0",
    integrations=[FlaskIntegration()]
)

app = Flask(__name__)
socketio = SocketIO(app)

@app.route('/')
def index():
    return '''
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
<script>
    var socket = io()
</script>

Bedarf:

flask
sentry-sdk[flask]
flask-socketio
eventlet

Beispiel Gunicorn-Konfiguration:

bind = '[::]:4444'
worker_class = 'eventlet'
accesslog = '-'

Beim Laden / wird eine Verbindung zum Websocket hergestellt. Beim Trennen des Websockets (z. B. wegnavigieren, aktualisieren) wird eine Ausnahme wie folgt erzeugt:

[2020-09-23 07:24:49 +0000] [16303] [ERROR] Error handling request /socket.io/?EIO=3&transport=websocket&sid=29f4c1adfac343d6bc6db56acf8fd0ee
Traceback (most recent call last):
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/workers/base_async.py", line 55, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/workers/base_async.py", line 115, in handle_request
    resp.close()
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 402, in close
    self.send_headers()
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 318, in send_headers
    tosend = self.default_headers()
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 299, in default_headers
    elif self.should_close():
  File "/home/ziddey/projects/sentry/venv_sentry/lib/python3.8/site-packages/gunicorn/http/wsgi.py", line 219, in should_close
    if self.status_code < 200 or self.status_code in (204, 304):
AttributeError: 'Response' object has no attribute 'status_code'
2001:470:1f07:7eb:9dd4:254c:35d7:236c - - [23/Sep/2020:07:24:49 +0000] "GET /socket.io/?EIO=3&transport=websocket&sid=29f4c1adfac343d6bc6db56acf8fd0ee HTTP/1.1" 500 0 "-" "-"

Hinweis: Ich habe Sentry selbst noch nie benutzt. Dies ist nur von der Sentry-Erste- Schritte -Seite. Das Beispiel dsn funktioniert gut für unseren Test.

Das Kommentieren integrations=[FlaskIntegration()] wird dann den Fehler beseitigen (natürlich effektiv Sentry deaktivieren).

Für das, was es wert ist, kann gevent-websocket anstelle von eventlet ohne Fehler verwendet werden. Allerdings scheint es dann alle Anfragen zu bearbeiten.

Ok, habe etwas rumgespielt. Sieht so aus, als ob Sentry/Newrelic die Antwort umschließt. Ohne Sentry erhalten wir wie erwartet <eventlet.wsgi._AlreadyHandled object at 0x7fd0f5b1c0d0> und Gunicorns EventletWorker.is_already_handled() stoppt die Iteration.

Wenn Sie jedoch Sentry verwenden, wird dies stattdessen zu etwas wie <sentry_sdk.integrations.wsgi._ScopedResponse object at 0x7f30155a5100> , wodurch die Überprüfung fehlschlägt

Stattdessen könnten wir einen Blick auf Respiter werfen, um zu sehen, ob er leer ist. Werde morgen weiter schauen.

Okay, hier ist die Problemumgehung, die ich mir ausgedacht habe:

eventlet_fix.py:
siehe Bearbeiten unten

Und in meiner gunicorn config.py: worker_class = 'eventlet_fix.EventletWorker .

Das Problem ist, dass sentry/newrelic die Antworten umschließt, sodass wir es nicht einfach mit ALREADY_HANDLED von eventlet vergleichen können. Da die Art einer bereits bearbeiteten Anfrage darin besteht, dass gunicorns start_response nicht aufgerufen wird, können wir stattdessen prüfen, ob ein Antwortstatus vorhanden ist.

Also habe ich den wsgi-Aufruf entführt, um dann nach einem Antwortstatus zu suchen und Antwortwerte nach Bedarf zu hacken. Dadurch kann die Anfrage weiterhin von Gunicorn protokolliert werden. Wenn stattdessen das ursprüngliche Verhalten beibehalten werden soll, kann stattdessen StopIteration ausgelöst werden.

Das Hacken des Status auf 101 ist für unseren Anwendungsfall hier angemessen (flask-socketio websocket), aber ansonsten funktioniert es auch, es auf None zu belassen, da headers_sent und should_close auf True gezwungen werden.

Auch hier wird davon ausgegangen, dass start_response nicht aufgerufen wurde, wenn status nicht gesetzt ist, und daher die Anfrage extern "bereits behandelt" worden sein muss.

edit: Nicht gut. Muss neu bewertet werden. Wenn die Ausführung der Anfrage einige Zeit in Anspruch nimmt, wird start_response nicht aufgerufen, bevor resp.status überprüft wird.

edit2: Hier ist eine korrigierte Version mit einem gehackten Response-Iterator:

from functools import wraps

from gunicorn.workers.geventlet import EventletWorker as _EventletWorker


class HackedResponse:
    def __init__(self, respiter, resp):
        self.respiter = iter(respiter)
        self.resp = resp
        if hasattr(respiter, "close"):
            self.close = respiter.close

    def __iter__(self):
        return self

    def __next__(self):
        try:
            return next(self.respiter)
        except StopIteration:
            if not self.resp.status:
                self.resp.status = "101"  # logger derives status code from status instead of using status_code
                self.resp.status_code = 101  # not actually needed since headers_sent/force_close result in status_code not being checked anymore
                self.resp.headers_sent = True
                self.resp.force_close()
            raise


def wsgi_decorator(wsgi):
    @wraps(wsgi)
    def wrapper(environ, start_response):
        respiter = wsgi(environ, start_response)
        resp = start_response.__self__
        return HackedResponse(respiter, resp)

    return wrapper


class EventletWorker(_EventletWorker):
    def load_wsgi(self):
        super().load_wsgi()
        self.wsgi = wsgi_decorator(self.wsgi)

Offensichtlich ist dies nur ein Affenfleck. Der eigentliche Fix könnte möglicherweise in handle_request in base_async.py einfließen. Der Schlüssel kann darin bestehen, (indirekt) zu prüfen, ob start_response aufgerufen wurde, nachdem respiter durchlaufen wurde, entweder durch Prüfen von resp.status (nur start_response aufgerufen) oder resp.headers_sent (Bestätigung, dass wir tatsächlich auf die Anfrage geantwortet haben).

@benoitc
@ziddey hat einen Weg gefunden, das Problem zu lösen.

@ziddey kurze Fragen für Ihr Beispiel (da ich keine Wache verwende).

  • Wirkt sich der Fehler nur auf Sentry aus oder wird die Anfrage auch gestoppt, dh der Worker wird beendet (was ich vermute, wenn die Antwort umschlossen ist)?
  • Erwarten Sie, dass dort etwas umschlossen ist, oder wenn die Anfrage bereinigt wird, wenn die Antwort umschlossen ist, wäre dies in Ordnung?

@benoitc derzeit nicht in der Lage zu testen, aber siehe Traceback oben https://github.com/benoitc/gunicorn/issues/1852#issuecomment -697189261 und https://github.com/benoitc/gunicorn/blob/4ae2a05c37b332773997f90ba7542713b9bf8274/ gunicorn/workers/base_async.py#L107 -L140

Normalerweise würde is_already_handled True zurückgeben und es würde einfach hier enden.

Da die Antwort jedoch umschlossen ist, funktioniert diese Methode nicht. Stattdessen wird die Ausführung fortgesetzt und schlägt in Zeile 115 fehl: resp.close() versucht, Header zu senden, aber start_response wurde nie aufgerufen, daher gibt es keinen Statuscode. Selbst wenn es das täte, würde es letztendlich offensichtlich scheitern.

Dies führt zu einem AttributeError, der erneut ausgelöst und vermutlich von handle_error behandelt wird. Da die Anfrage bereits extern behandelt wurde, kann hier außer Log-Spam nichts schaden.

Ich kann nicht zu viel über Sentry sagen – ich benutze es auch nicht.

Ein Detail jedoch: Der derzeitige bereits behandelte Mechanismus führt zu keiner Zugriffsprotokollierung. Ich nehme an, dass dies technisch sinnvoll ist, da es keine Möglichkeit gibt zu wissen, wie es extern gehandhabt wurde. In meiner gehackten Antwort erzwinge ich den Statuscode auf 101, mit headers_sent als True, damit der Handler fortfahren kann und die Anfrage weiterhin protokolliert wird.

Das Überprüfen resp.status ist ein definitiver Test, um festzustellen, ob start_response wurde.

@benoitc greift dies noch einmal auf. Um definitiver zu dem Schluss zu kommen, dass die Anfrage bereits bearbeitet wurde, könnte environ['gunicorn.socket'] stattdessen eine Art Proxy für das zugrunde liegende Objekt sein. Auf diese Weise kann es aufgezeichnet werden, wenn direkt auf den Socket zugegriffen wird (z. B. get_socket() für Eventlet umschließen), und für etwas wie is_already_handled verwendet werden

Es würde jedoch immer noch das Hacken eines Antwortstatus erfordern, wenn eine Zugriffsprotokollierung gewünscht wird.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen