web-dev-qa-db-ja.com

ハイパーリンクをクリックした場合、ブラウザに追加のHTTPヘッダーを送信させる

ユーザーがリンクをクリックしたときに、Webブラウザーが追加のHTTPヘッダーを送信する方法はありますか?

背景:この環境では、すべてのhttp-requestにサーバー側で一意のIDがあります。 https://serverfault.com/questions/797609/Apache-x-request-id-like-in-herok を参照してください

Webアプリケーションがhttp-requestを受け取った場合、どのページが以前のページだったかを知りたいです。 ユーザーがブラウザで複数のタブを使用できるため、httpリファラーでは不十分です。

ブラウザからサーバーに送信されるすべてのGETリクエストにいrequest-idを配置することは避けたいと思います。これまでのところ、URLは素晴らしいものです。

私が好む解決策は、現在のページのrequest-idを次のhttpリクエストに追加するJavaScriptマジックです。

詳細な手順:

  1. ブラウザアクセスURL http://example.com/search
  2. webサーバーはリクエストID 123のHTTPリクエストを受信します
  3. webサーバーは、URLのコンテンツをブラウザー(検索ページ)に送信します。ページにはどこかにリクエストID 123が含まれています
  4. ユーザーは「foobar」を検索します。
  5. webブラウザーはhttpリクエストをサーバーに送信し、何らかの形で以前のリクエストIDを含めます。
  6. webサーバーは2番目のhttp要求(ID 456)を受信し、何らかの方法で最初の要求の値(ID 123)にアクセスできます。
  7. Webサーバーは、後で分析するために、リレーションシップ "123-> 456"をデータベースに保存できます。

私の目標は、リレーションシップ「123-> 456」を追跡することです。上記のソリューションは、目標を達成するための戦略にすぎません。他の戦略も歓迎します。

WebフレームワークDjangoを使用します。しかし、これはこのコンテキストでは重要です。

ユーザーはブラウザで複数のタブを使用できます

マッチングソリューションにとってそれが何を意味するかを詳しく説明します。 1人のユーザーからのリクエストのシーケンスは問題を解決しません。

複数のタブを使用する1回の使用:

  1. ユーザーはtab1のページAを見る
  2. ユーザーはtab2のページBを見る
  3. ユーザーがページAからページCへのリンクをたどる
  4. ユーザーはページCからページDへのリンクをたどります
  5. ユーザーはページB(tab2)のリンクをたどってページEに移動します。

2つのシーケンスが表示されることを知りたい:

A -> C -> D

そして

B -> E
13
guettli

ここでの唯一の最新の「健全な」オプションは、ServiceWorkerを使用することです。

ServiceWorkerは、制御するドメインのHTTP要求をインターセプトし、より多くのヘッダーで装飾できます。

ServiceWorkerはブラウザータブの「外側」で動作し、同じWebサイトで複数のタブが開いている場合、すべてのタブに同じserviceworkerが使用されます。

これを達成する方法に関する完全なチュートリアルは、この回答ボックスには間違いなく多すぎますが、HTTPリクエストを傍受して処理することは大きなユースケースです。

これはちょっと悪い考えだと思います。これが必要だと思われる場合は、別の方法で処理できます。これを行う一般的な方法は、代わりにCookieを使用することです。

10
Evert

まず第一に、私の英語を申し訳ありません。

編集:

編集内容を読んだ後、タブが原因で私の答えがまったく合わないことに気付きました。

ブラウザがgetリクエストを行う方法を直接変更することはできません。それを知って、あなたの可能性は:

  • GETパラメーターを使用します。これを避けようとしているのは知っています。
  • @Evertが言ったように、ServiceWorkersを使用します。これは、ブラウザを離れる前にリクエストを変更する最もクリーンな方法です。
  • 最後のアプローチ(簡単な方法)は@Emeeusに似ていますが、値がタブ間で共有されるlocalStorageを使用する代わりに、値がsessionStorageを使用する必要がありますタブに依存しない。また、ルート全体を保存する代わりに、ランダムIDのみを保存する必要があります。このIDは、特定のタブに対するリクエストのチェーンの識別として機能します。次に、たとえばRequest-IDを使用して、Webサーバーが各<meta name="request_id" content="123" />を返すと、特定の追跡エンドポイントとストアにajax経由でリクエストを行うだけで済みます:
    • chain_id(sessionStorageに保存)
    • request_id(headに格納> meta)
    • タイムスタンプ(ウェブサーバーで生成)
    • session_id(ウェブサーバーからアクセス可能)。これは回避できますが、チェックの目的には依然として役立ちます。

ルートを保存するリクエストは、ページのロード前ではなくロード後に行われます。このアプローチは、Analyticsの動作に非常に似ています。

// 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'),
        }
    });
});

注:JQueryを使用して追跡要求を処理しないでください。ドキュメントが完全にロードされるまで待機することもできません。これは単なる例です。

そしてそれだけです。ユーザーエージェント、チェーン、リクエスト、リクエストのタイムスタンプの間に関係があるので、特定のリクエストの前後にどのリクエストが行われたかを知る必要がある場合、 Chain-IDとタイムスタンプをフィルターとして使用してデータベースを検索するだけです。

Djangoリクエストのモデルは可能性があります。

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)

役に立てば幸いです。

1
ddiazp

これが役立つかどうかはわかりませんが、リクエストIDに関しては、onclickイベントリスナー内に追加のヘッダーを設定するなど、Ajaxが役立つと思います。ずっといい ...

0