Gibt es eine Möglichkeit, eine verweisende URL über einen benutzerdefinierten HTTP-Header abzurufen?

8

Ich verwende derzeit die folgende Funktion, um eine verweisende Ansicht zu erhalten:

def get_referer_view(request, default=None):   
    referer = request.META.get('HTTP_REFERER')
    if not referer:
        return default

    # remove the protocol and split the url at the slashes
    referer = re.sub('^https?:\/\/', '', referer).split('/')
    if referer[0] != request.META.get('SERVER_NAME'):
        return default

    # add the slash at the relative path's view and finished
    referer = u'/' + u'/'.join(referer[1:])
    return referer

Wenn ich das viewals Ergebnis programmatischer Logik umleitete , z.

return HttpResponseRedirect('dashboard')

... gibt es eine Möglichkeit, die verweisende Ansicht ohne Verwendung HTTP_REFERERabzurufen, damit ich diese Variable in der umgeleiteten verwenden kann view? Dies wird nicht immer in den Headern des Browsers festgelegt.

Beachten Sie, dass ich POST nicht zum Sammeln der Daten verwenden kann, da die Ansichten programmgesteuert umgeleitet werden.

Vielleicht ist es möglich, einen benutzerdefinierten Header irgendwie zu setzen und abzurufen?

alias51
quelle
1
Kontrollieren Sie die vorherige Ansicht und sie stammt aus Ihrer Anwendung? Ich würde diese Informationen einfach in die Nutzlast und Antwort einfügen. ZB als Umleitungsparameter GET ?came_from=inbox. Verknüpft, Facebook, andere scheinen es zu tun, also sollte es in Ordnung sein, zu üben.
Mikko Ohtamaa
1
@ MikkoOhtamaa ja, ich kontrolliere die Ansicht. Der Anwendungsfall ist normalerweise eine bedingte Logikumleitung. Idealerweise möchte ich die URL trotzdem sauber halten.
alias51
GET-Abfrageparameter sind der richtige Weg. Alternativ können Sie versuchen, einige Statusinformationen in den Benutzersitzungsdaten zu speichern. Diese fallen jedoch normalerweise auseinander, wenn der Benutzer mehrere Browserfenster geöffnet hat und widersprüchliche Überschreibungen von Sitzungsvariablen vorliegen.
Mikko Ohtamaa
HttpResponseRedirectist nicht wirklich programmatisch - es gibt die tatsächliche http 302-Antwort zurück und zwingt den Browser, eine neue Anfrage an die neue URL der Ansicht zu
richten,

Antworten:

2

Verwenden Sie die Middleware-Komponente von Django.

https://docs.djangoproject.com/de/3.0/topics/http/middleware/

So etwas sollte funktionieren:

class HTTPReferer:

    def __init__(self, get_response):
        self.get_response = get_response

def __call__old(self, request):
    # old
    referer = request.META.get('HTTP_REFERER', None)
    request.referer = referer
    # other business logic as you like it
    response = self.get_response(request)
    return response

def __call__(self, request):
    # reflecting last edit
    path = request.path
    response = self.get_response(request)
    response['previous_path'] = path
    return response

So können Sie alle benötigten Informationen mit jedem Anforderungs- / Antwortzyklus in Django verknüpfen (Sie können auch benutzerdefinierte Header usw. festlegen).

Im obigen Beispiel HTTP_REFERERwird im Anforderungsobjekt als verfügbar sein referer.

EDIT: Ich denke, Sie befürchten, dass HTTP_REFERERnicht immer vom Kunden bevölkert wird; Sie können also HttpRequest.path an jede Anforderung an einen benutzerdefinierten Header binden . Wenn der Pfad nicht ausreicht, können Sie auch die Anforderungsargumente speichern. Das ist alles was ich denke. Dann haben Sie einen benutzerdefinierten Header, der mit dem letzten Pfad gefüllt ist. Wenn dies nicht ausreicht, können Sie den URL-Resolver von Django verwenden .

Jazz
quelle
Danke, aber meine Frage wird explizit gestellt, ohne HTTP_REFERER
alias51 zu verwenden.
@ alias51, ich verstehe, aber da Sie die volle Kontrolle über den Anforderungs- / Antwortzyklus haben, warum verwenden Sie nicht stattdessen einen benutzerdefinierten Header? Gefällt mir: Antwort ['I-AM-TRACKING-ETWAS-IN-A-STATELESS-PROTOCOL'] = 'WAS auch immer Sie brauchen'. Ich werde meine Antwort ändern.
Jazz
1

Da Sie die Seite steuern, auf der die Anfrage gestellt wird, ist dies sicher. Fügen Sie die aktuelle URL zu einem Header hinzu und extrahieren Sie sie in Ihrer Funktion, ähnlich wie folgt: Fügen Sie den Anforderungsheader vor der Umleitung hinzu

also stattdessen:

def current_view():
   ...
   return HttpResponseRedirect('dashboard')

mach so etwas:

def current_view():
    ...
    response = redirect('/dashboard')
    response['source-view'] = request.resolver_match.view_name
    return response

Dies sollte den 302 mit dem benutzerdefinierten Header erzeugen source-view, den Sie in der Empfangsansicht extrahieren können

stringy05
quelle
0

Für Interessierte ist hier die Lösung, die ich abgeleitet habe. Der Trick besteht darin, nach der ersten Anforderung zum Speichern des view_nameoder ein Cookie zu setzen pathund es dann aufzurufen und im zu speichern, requestbevor die Ansicht gerendert wird.

class MyMiddleware:

    def __init__(self, get_response):
        # One-time configuration and initialization.
        self.get_response = get_response

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        # Add the referer cookie be accessible in request.response
        request.referer_view = request.COOKIES.get('referer_view', None)
        request.referer_path = request.COOKIES.get('referer_path', None)
        print('request.referer_view', request.referer_view)
        print('request.referer_path', request.referer_path)

        response = self.get_response(request)
        # Code to be executed for each request/response after
        # the view is called.

        # Set a cookie with the current view name that is cleared each time the view changes
        response.set_cookie('referer_view', request.resolver_match.view_name)
        response.set_cookie('referer_path', request.path)

        return response

Die Werte werden dann in diesem Zyklus jedes Mal aktualisiert, wenn die Ansicht geändert wird.

alias51
quelle
1
Der Punkt ist, dass Sie die Lösung haben, die die Richtung dazu erhält. Wenn Sie Cookies aus geschmacklichen Gründen einem benutzerdefinierten Header vorziehen, hätte ich den benutzerdefinierten Header aus gestalterischer Sicht vorgezogen, da der vorherige Pfad flüchtig ist und das Speichern dieser Informationen in Cookies überflüssig ist. Ich bin froh, Ihnen geholfen zu haben :-) Ich habe Ihre "Lösung" zu spät gesehen, sonst würde ich meine Antwort nicht bearbeiten.
Jazz
Danke, warum denkst du, dass request.path volatil ist? Der Grund, warum ich anstelle des Headers ein Cookie verwende, ist, dass Header leicht manipuliert werden können und daher weniger sicher sind.
alias51