Existe-t-il un moyen de faire en sorte que le navigateur Web envoie un en-tête HTTP supplémentaire si l'utilisateur clique sur un lien?
Contexte: Dans notre environnement, chaque requête http a un identifiant unique côté serveur. Voir https://serverfault.com/questions/797609/Apache-x-request-id-like-in-heroku
Si votre application Web reçoit une requête http, j'aimerais savoir quelle page était la page précédente. Le référent http ne suffit pas, car l'utilisateur peut utiliser plusieurs onglets dans son navigateur.
Je voudrais éviter de mettre l'id de demande-laid dans chaque demande GET qui est envoyée par le navigateur au serveur. Jusqu'à présent, nos URL sont Nice.
Ma solution préférée serait une certaine magie JavaScript qui ajoute l'identifiant de la demande à la page actuelle dans la prochaine requête http.
Étapes en détail:
Mon objectif est de suivre les relations "123 -> 456". La solution ci-dessus n’est qu’une stratégie pour atteindre l’objectif. D'autres stratégies sont les bienvenues.
Nous utilisons le framework web Django. Mais autant que je sache, cela compte dans ce contexte.
l'utilisateur peut utiliser plusieurs onglets dans son navigateur
Je précise ce que cela signifie pour une solution correspondante. La séquence de demandes émanant d’un utilisateur ne résout pas le problème.
Une utilisation avec plusieurs onglets:
Je veux savoir voir deux séquences:
A -> C -> D
Et
B -> E
La seule option «rationnelle» moderne consiste ici à utiliser un ServiceWorker.
Un ServiceWorker peut intercepter les demandes HTTP d'un domaine que vous contrôlez et le décorer avec plusieurs en-têtes.
Un ServiceWorker fonctionne "en dehors" d'un onglet de navigateur, et si plusieurs onglets sont ouverts avec le même site Web, le même serviceworker sera utilisé pour tous.
Un didacticiel complet sur la façon de procéder est certainement trop compliqué pour cette boîte de réponse, mais intercepter et traiter des requêtes HTTP est un cas d'utilisation très volumineux. Par conséquent, les sources hors site le prennent généralement pour exemple.
Je dirais que c'est un peu une mauvaise idée. Si vous pensez en avoir besoin, vous pouvez peut-être gérer cela différemment. Une méthode courante consiste à utiliser des cookies.
Tout d'abord, désolé pour mon anglais.
Après avoir lu votre édition, je me suis rendu compte que ma réponse ne correspondait pas du tout, à cause des onglets.
Il n’est pas possible de modifier directement la manière dont le navigateur fait une demande d’obtention. Sachant cela, vos possibilités sont:
localStorage
, dont les valeurs sont partagées entre les onglets, vous devez utiliser sessionStorage
, dont les valeurs sont indépendantes de tabulation . En outre, au lieu de stocker la totalité de l'itinéraire, vous devez stocker uniquement un ID aléatoire. Cet identifiant fonctionnera comme l'identification de la chaîne de demandes pour un onglet spécifique. Ensuite, une fois que votre serveur Web renvoie chaque Request-ID
, par exemple en utilisant <meta name="request_id" content="123" />
, il vous suffit de faire une demande via ajax à un point de terminaison de suivi spécifique et de stocker: La demande de stockage de l'itinéraire est faite après le chargement de votre page, au lieu d'avant. Cette approche est assez similaire à la façon dont Analytics fonctionne.
// generate an unique code and store it in sessionStorage.
if (!sessionStorage.getItem('chain_id')) {
sessionStorage.setItem('chain_id', 'a7835e0a-3ee9-e981-...');
}
// Then, if you use JQuery:
$(document).ready(function() {
$.ajax({
type: "POST",
url: 'your/tracking/endpoint/',
data: {
'chain_id': sessionStorage.getItem('chain_id'),
'request_id': document.querySelector("meta[name='request_id']").getAttribute('content'),
}
});
});
Remarque: Il est préférable de ne pas utiliser JQuery pour traiter les demandes de suivi, ni d'attendre que le document soit complètement chargé. C'est juste un exemple.
Et c'est tout. Vous avez la relation entre l'agent utilisateur, la chaîne, la requête et l'horodatage de la requête. Par conséquent, si vous avez besoin de savoir quelle requête a été faite avant ou après une requête donnée, il vous suffit de rechercher dans la base de données à l'aide de la commande Chain-ID
et l'horodatage en tant que filtres.
from Django.db import models
from Django.contrib.sessions.models import Session
class Request(models.Model):
session = models.ForeignKey(Session)
chain_id = models.Charfield(max_length=100)
request_id = models.WhatEverField...
request_url = models.URLField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
J'espère que ça aide.
Nous pouvons modifier les en-têtes de requête en utilisant:
Il n'est pas possible (à l'aide de javascript) de modifier les en-têtes envoyés par le navigateur dans une requête telle que <a href=""></a>
car, à tout le moins, la négociation de contenu http est une fonctionnalité interne du navigateur (sauf l'utilisation partielle de XMLHttpRequest dans same ou origines autorisées ).
Ensuite, à mon avis, comme @Evert l’a dit, vous disposez de deux méthodes pratiques (la troisième en fait) pour atteindre votre objectif, effectuer un proxy de serveur ou utiliser des cookies. Ici vous avez un moyen très simple d’utiliser window.localStorage } _:
Exemple de LocalStorage
if (!localStorage.getItem("ids")) {//<-- the place in which we store the behavior
localStorage.setItem("ids", 'somevalue')
} else {
var ids = JSON.parse(localStorage.getItem("ids"));
ids.ids.Push(id);//<-- we add some value
localStorage.setItem("ids", JSON.stringify(ids));
}
Exemple complet ici: https://jsfiddle.net/hy4rzob9/ appuyez plusieurs fois et vous verrez que nous enregistrons chaque visite, bien sûr, dans votre implémentation, vous devez remplacer le nombre aléatoire par un nombre aléatoire. identifiant unique de chaque page.
Exemple LocalStorage avec plusieurs onglets
En prenant en compte la mise à jour, nous pourrions stocker l’historique en utilisant aussi document.referrer
avec localStorage
avec quelque chose comme ceci:
var session = Math.random();
if(!localStorage.getItem("routes")){//<-- first time
var routes = {};
routes[session] = [document.location.href];
localStorage.setItem("routes", JSON.stringify(routes))
}else{
var routes = JSON.parse(localStorage.getItem("routes"));
if(!document.referrer){
routes[session] = [document.location.href];//<-- new root
}else{
for(let ses in routes){
if(routes[ses].includes(document.referrer)){
routes[ses].Push(document.location.href);
}
}
}
localStorage.setItem("routes", JSON.stringify(routes))
}
var r = JSON.parse(localStorage.getItem("routes"));
console.log(r);
Exemple complet ici (https://codesandbox.io/s/qk99o4vy7q }, pour émuler votre exemple, ouvrez cette https://qk99o4vy7q.codesandbox.io/a.html } _ (représente A) et ouvrez un nouvel onglet https://qk99o4vy7q.codesandbox.io/b.html (représente B), naviguez dans les deux onglets et voyez la console. Cet exemple ne fonctionnera pas si nous partageons un référent, car nous ne pouvons pas différencier les référents si nous n'attachons rien dans l'URL. A -> C -> D et B -> E fonctionneront, mais A -> C -> D et B -> E -> A ne fonctionneront pas.
Exemple de ping
Il y a un autre moyen, facile mais avec une limitation de compatibilité du navigateur , qui utilise l'attribut ping
de <a>
comme ceci:
<a href="https://www.google.com/" ping="trackPing.py">Link to track</a>
ping Contient une liste d'URL séparées par des espaces auxquelles, lorsque lien hypertexte est suivi, les demandes POST avec le corps PING seront envoyées par le navigateur (en arrière-plan). Généralement utilisé pour le suivi.
Ouvrez la console -> réseau, supprimez tout, lancez l'extrait de code et cliquez sur le lien. Si votre navigateur le prend en charge, vous verrez qu'il envoie une demande POST à trackPing.py
(je suppose qu'il n'existe pas dans SO. ), cet article est annulé, mais vous pouvez suivre les variables environnementales telles que request.environ['REMOTE_ADDR']
ou quelque chose du genre.
Je ne sais pas si cela aidera, mais je pense que peut-être Ajax fera: Comme définir un en-tête supplémentaire dans l'écouteur d'événement onclick, comme pour l'id de la demande, si ce n'est pas quelque chose de si sensible, vous pouvez utiliser un cookie pour le conteneur, ou peut-être quelque chose de beaucoup mieux ...