¿Hay alguna manera de obtener una URL de referencia a través de un encabezado HTTP personalizado?

8

Actualmente estoy usando la siguiente función para obtener una vista de referencia:

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

Si redirigí el viewcomo resultado de la lógica programática, por ejemplo ...

return HttpResponseRedirect('dashboard')

... ¿hay alguna manera de obtener la vista de referencia sin usar HTTP_REFERERpara poder usar esa variable en el redireccionado view? Esto no siempre se establece en los encabezados del navegador.

Tenga en cuenta que debido a que las vistas se redirigen programáticamente, no puedo usar POST para recopilar los datos.

¿Quizás es posible establecer y recuperar un encabezado personalizado de alguna manera?

alias51
fuente
1
¿Controlas la vista anterior y proviene de tu aplicación? Simplemente agregaría esta información en la carga útil y la respuesta. Por ejemplo, como un parámetro GET de redireccionamiento ?came_from=inbox. Linked, Facebook, otros parecen hacerlo, por lo que debería ser una buena práctica.
Mikko Ohtamaa
1
@MikkoOhtamaa sí, controlo la vista. El caso de uso es típicamente una redirección lógica condicional. Sin embargo, idealmente me gustaría mantener limpia la URL.
alias51
Los parámetros de consulta GET son el camino a seguir. Alternativa, puede intentar esconder cierta información de estado en los datos de la sesión del usuario, pero generalmente se desmorona cuando el usuario tiene abiertas varias ventanas del navegador y hay sobrescrituras conflictivas a las variables de sesión.
Mikko Ohtamaa
HttpResponseRedirectno es realmente programático: devuelve la respuesta http 302 real y obliga al navegador a hacer una nueva solicitud a la nueva URL de la vista a la que se está redirigiendo ...
Oleg Russkin

Respuestas:

2

Use el componente de middleware de Django.

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

Algo como esto debería funcionar:

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

Por lo tanto, puede vincular cualquier información que necesite a cada ciclo de solicitud / respuesta en Django (también puede configurar encabezados personalizados, etc.)

En el ejemplo anterior HTTP_REFERERestará disponible en el objeto de solicitud como referer.

EDITAR: Creo que su preocupación es que HTTP_REFERERno siempre está poblada por el cliente; para que pueda vincular HttpRequest.path a cada solicitud realizada a un encabezado personalizado. Si la ruta no es suficiente, también puede guardar los argumentos de la solicitud. Eso es todo, creo. Luego tiene un encabezado personalizado poblado por la última ruta. Más adelante, si esto no es suficiente, puede usar el solucionador de URL de Django .

jazz
fuente
Gracias, pero mi pregunta se hace explícitamente sin usar HTTP_REFERER
alias51
@ alias51, entiendo, pero como tienes control total sobre el ciclo de solicitud / respuesta, ¿por qué no utilizas un encabezado personalizado? Me gusta: respuesta ['I-AM-TRACKING-SOMETHING-IN-A-STATELESS-PROTOCOL'] = 'LO QUE USTED NECESITA'. Enmendaré mi respuesta.
jazz
1

Como controlas la página que realiza la solicitud, seguro. Agregue la URL actual a algún encabezado y extráigala en su función, similar a esto: Agregue el encabezado de solicitud antes de la redirección

así que en lugar de esto:

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

haz algo como esto:

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

Esto debería producir el 302 con el encabezado personalizado source-view, que puede extraer en la vista de recepción

stringy05
fuente
0

Para aquellos interesados, aquí está la solución que obtuve. El truco consiste en establecer una cookie después de la primera solicitud para almacenar el view_nameo pathy luego llamarlo y guardarlo requestantes de mostrar la vista.

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

Los valores se actualizan en este ciclo cada vez que se cambia la vista.

alias51
fuente
1
El punto es que tienes la solución para obtener la dirección. Si prefiere cookies sobre un encabezado personalizado, por gusto, hubiera preferido el encabezado personalizado desde una perspectiva de diseño, ya que la ruta anterior es volátil y el almacenamiento de esta información en cookie es redundante. Me alegra haberte ayudado :-) Vi tu "solución" demasiado tarde, de lo contrario, no editaría mi respuesta.
jazz
Gracias, ¿por qué crees que request.path es volátil? La razón por la que uso una cookie en lugar del encabezado es que los encabezados se pueden manipular fácilmente y, por lo tanto, son menos seguros.
alias51