1941


Webページのリンク先ページを表示する方法として、リンクを直接クリックするだけでなく、右クリックから「新しいタブで開く」「新しいウィンドウで開く」で開いたり、新しいタブ（ウィンドウ）を開いてアドレスバーにリンク先のURLを直接貼り付けるなど、様々な方法があると思いますが、どのような方法で表示したかを（サーバーサイドで）識別する方法はあるでしょうか？

  * 二重起動の抑止
  * 複数タブの識別

などが目的です。

リンクを直接クリックしたかどうかは、clickイベントでhref属性を書き換える（適当なパラメータを後ろにつけるとか）ことで分かりそうですが、他に方法があるでしょうか。


CC BY-SA 3.0
2014-12-17T15:06:31.163
1935
2014-12-17T18:25:44.990
3925
question
javascript html
リンクを新しいタブ、新しいウィンドウで開いたことを識別する方法


ページが開かれた方法を識別する方法は思いつきませんが、二重起動の抑止や複数タブの識別ということであれば、Shared
Workerをなんとかすればできそうな気がします。

<http://javascript.g.hatena.ne.jp/edvakf/20100315/1268690860>

問題は、ブラウザサポートがあまりないことなので、コンシューマー向けにはあまり実用的ではないかも。
<http://caniuse.com/#feat=sharedworkers>

複数ブラウザが開かれていることを想定したくないとすれば、全体の設計を考え直した方が良いように思います。


CC BY-SA 3.0
2014-12-17T16:06:43.290
1939
2014-12-17T16:06:43.290
71
1935
answer


アプリケーションを作成する際にはなるべくセッションに情報をもたず、複数ブラウザを起動（タブの複製を含む）しても問題ないように作れればベストです。しかし、セッションにいろいろな情報を持ってしまうと状態の整合性を保つために、二重起動を抑止する必要がでてくると思うのですが、その対応だと仮定してお答えします。

二重起動を抑止するためには、タブを開いたか、二重に起動したかを直接チェックすることは一般的ではありません。

  1. クライアントサイドで、必ずワンタイムトークンをリンクやフォームなどに付与します。
  2. サーバサイドでもセッションにワンタイムトークンを格納しておきます。
  3. クライアントからのリクエストを処理する際、リクエストに含まれているワンタイムトークンとセッションに含まれているワンタイムトークンが正しいかどうかを確認します。

こうすることで、タブでリンクを開いたときには正常に表示されますが、もともとのタブで遷移しようとすると、ワンタイムトークンは無効となっているので、サーバサイドで無効なリクエストとして処理することができます。結果としてタブを開くことはできてしまいますが、アプリケーションの整合性を保つことができます。


CC BY-SA 3.0
2014-12-17T16:19:27.560
1940
2014-12-17T16:19:27.560
2298
1935
answer


開かれるページに、次のようなJavaScriptを仕込みます。

[code]

    if (document.referrer) {
        if (history.length == 1) {
            alert('リンクから新しいウィンドウで開かれました。');
        } else {
            alert('リンクから同じウィンドウで開かれました。');
        }
    } else {
        alert('アドレスバーにURLを打ち込んで開かれました。もしくはブックマークから開かれました。');
    }
    
[/code]

この例ではalertですが、Ajaxなどでサーバに通知できると思います。


CC BY-SA 3.0
2014-12-17T16:26:09.903
1941
2014-12-17T16:34:34.727
2014-12-17T16:34:34.727
4379
4379
1935
answer


localStorage はタブ・ウィンドウ間を通して値を共有できます。

[code]

    // localStorageに値があれば二重起動
    if (localStorage.getItem('running')) {
      alert('新しいタブまたは新しいウィンドウで開きました');
    }
    
    // 値を設定 (ここでは単に true とします)
    localStorage.setItem('running', true);
    
    // いつまでも残るので unload または beforeunload で消す
    window.addEventListener('beforeunload', function() {
      localStorage.removeItem('running');
    }, false);
    
[/code]


CC BY-SA 3.0
2014-12-17T18:25:44.990
1945
2014-12-17T18:25:44.990
4106
1935
answer