ホームページ > 記事 > ウェブフロントエンド > TIL: JavaScript でタブをブロックして IP を取得する
「今日学んだこと」シリーズの第 1 回へようこそ!これらの投稿を通じて、アルゴリズム エンジニアとしての仕事中に得た実践的な洞察を共有し、現実世界の課題に対処するために私が実装したテクニックを詳しく掘り下げていきます。これらのレッスンがあなたのプロジェクトにも価値をもたらすことを願っています。
説明のために、顔認識テクノロジーに関連する私が取り組んだプロジェクト、特に処理を合理化し、ユーザー全体のパフォーマンスを維持するために必要な手順を順を追って説明します。
この例では、Web ブラウザーからアクセスできる顔認識アプリケーション (チェックイン チェックアウト システム) を作成することがタスクでした。アプリケーションは次のことを行う必要がありました:
アプリケーションは 2 つの主要コンポーネントで設計されています:
わかりやすくするために、サーバーに送信する前にクライアントが顔を検出して検証し、サーバーが結果を返し、ブラウザーがそれを表示すると想像してください。
最近、出退勤の記録に新しい顔認識 Web アプリを使い始めた典型的なユーザー、アレックスを想像してみてください。ある朝、Alex は、一度に複数のタブでテストすることでチェックインを高速化できると考え、いくつかのブラウザ タブでアプリを開くことにしました。
ほぼ即座に、事態は下り坂になりました。各タブが読み込まれると、アプリの顔検出および検証プロセスが個別に初期化されます。アレックスは、コンピュータの速度が大幅に低下し、最終的にはブラウザの動作が遅くなり始めたことに気づきました。舞台裏では、これらの複数のタブがそれぞれアレックスの顔を処理するためにリソースを使用しており、デバイスのパフォーマンスに大きな影響を与えていました。
しかし、問題はそこで終わりませんでした。各タブが個別の認識リクエストをサーバーに送信すると、アプリのサーバー負荷が急増し、同時にログインする他のユーザーに遅延が発生しました。サーバーは重複したリクエストに圧倒され、ほとんど対応できず、遅延やチェックインの欠落が発生しました。
状況をさらに混乱させるために、各タブに異なる、一貫性のないログイン ステータスが表示されていました。 Alex は、アプリを複数のタブで開くと不必要な頭痛の種となり、会社全体に潜在的な問題を引き起こすことにすぐに気づきました。
シームレスな機能を確保し、クライアントとサーバーの両方のリソースへの不必要な負担を避けるために、ユーザーがアプリケーションで複数のタブを開けないようにする必要がありました
目的は、主に同じアプリの他のタブが既に開いていることを検出することにより、ユーザーがブラウザーでアプリの複数のインスタンスを同時に開くことを制限することでした。これに対処する方法は次のとおりです:
if (localStorage.getItem('isAppRunning') === 'true') { alert("The application is already open in another tab. Please close this tab."); } else { // Set a flag in localStorage to indicate the app is running localStorage.setItem('isAppRunning', 'true'); // Add an event listener to clear the flag when the tab is closed window.addEventListener('beforeunload', () => { localStorage.removeItem('isAppRunning'); }); // Main function to load models and start video if the app is not running in another tab (async function main() { try { const config = await loadConfig(); // Load models concurrently const [tinyFaceDetector, fasnet, phoneDetect] = await Promise.all([ loadTinyFaceDetector(), loadFasnet(config), loadPhoneDetect(config), ]); Object.assign(window, { fasnet, phoneDetect, config }); startVideo(); } catch (err) { console.error('Initialization failed:', err); } })(); }
当社の顔認識システムでは、承認された部門固有のアクセスのみを許可するように要件が進化しました。たとえば、担当者 A が部門 A に所属している場合、部門 A のネットワーク内のデバイスにのみチェックインまたはチェックアウトできる必要があり、部門 B やその他の部門ではチェックインまたはチェックアウトできません。これらのコンピューターはローカル エリア ネットワーク (LAN) を介して接続されているため、デバイスの IP アドレスに基づいてアクセスを識別し、制限する方法が必要です
オンラインで検索すると、IP アドレスの取得に関する情報が得られました。しかし、いくつか問題があります
function user_location() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { console.log( this.responseText); } }; xhttp.open("GET", "//api.ipify.org?format=json", true); xhttp.send(); }
この関数はユーザーのパブリック IP アドレスを正常に取得します。ただし、部門固有のアクセス制御に必要な内部 LAN IP アドレスは提供されません。さらに、VPN やファイアウォールによるマスキングの影響を受けやすくなります。
あるいはこれかもしれません
Firefox と Chrome は、ユーザーのローカル IP アドレスとパブリック IP アドレスを返す STUN サーバーへのリクエストを実行できる WebRTC を実装しました
しかし、アプリにこれ以上パッケージを追加したくありません。この複雑さと、ブラウザ間で不一致が生じる可能性があるため、あまり望ましくありません。
その後、この投稿を見つけました
ブラウザで実行されている JavaScript を使用してクライアントの IP アドレスを直接取得するのは簡単ではありません。これは、JavaScript が IP アドレスが公開されるネットワーク層にアクセスできないためです。さらに、セキュリティ上の理由から、ブラウザは JavaScript 環境をサンドボックス化し、クライアントの IP アドレスを含む特定のシステムレベルの情報にアクセスできないようにします。
JavaScript だけを使って IP アドレスを取得するのは不可能であることがわかりました。ただし、簡単な解決策があります。それは、サーバー上に API エンドポイントを作成してユーザーの IP アドレスを取得することです。
if (localStorage.getItem('isAppRunning') === 'true') { alert("The application is already open in another tab. Please close this tab."); } else { // Set a flag in localStorage to indicate the app is running localStorage.setItem('isAppRunning', 'true'); // Add an event listener to clear the flag when the tab is closed window.addEventListener('beforeunload', () => { localStorage.removeItem('isAppRunning'); }); // Main function to load models and start video if the app is not running in another tab (async function main() { try { const config = await loadConfig(); // Load models concurrently const [tinyFaceDetector, fasnet, phoneDetect] = await Promise.all([ loadTinyFaceDetector(), loadFasnet(config), loadPhoneDetect(config), ]); Object.assign(window, { fasnet, phoneDetect, config }); startVideo(); } catch (err) { console.error('Initialization failed:', err); } })(); }
クライアントがリクエストを行うと、Flask はリクエスト オブジェクトにさまざまなヘッダーと接続の詳細を自動的に入力します。
まず、コードは client_ip = request.headers.get('X-Forwarded-For') を使用して X-Forwarded-For ヘッダーをチェックします。
目的: このヘッダーは通常、元のクライアント IP アドレスを保持するためにプロキシまたはロード バランサーによって設定されます。リクエストがプロキシまたはロード バランサーを通過した場合、クライアントの実際の IP アドレスがこのヘッダーに表示される必要があります。
X-Forwarded-For ヘッダーが見つかった場合、client_ip はその値に設定されます。
X-Forwarded-For ヘッダーが欠落している場合 (たとえば、クライアントがプロキシを使用せずに直接接続している場合)、コードは request.remote_addr を使用してクライアントから IP アドレスを直接取得します。
この投稿では、Web ベースの顔認識アプリの開発における現実世界の課題に取り組んだ私の経験を共有します。私たちが解決した 2 つの重要な問題は次のとおりです:
複数のタブ インスタンスの防止: ユーザーが複数のブラウザー タブでアプリを開かないようにするために、localStorage を使用してアプリがすでに開いているかどうかを追跡します。これにより、クライアントとサーバーの両方のリソースに負担をかける冗長な顔検出プロセスが防止されます。
ユーザー IP アドレスの取得: セキュリティ制限のため、JavaScript はデバイスの LAN IP に直接アクセスできないため、サーバー上に API エンドポイントを設定して、リクエスト ヘッダーから IP を取得します。このアプローチにより、承認されたデバイスのみに対する部門固有のアクセス制御が保証されます。
以上がTIL: JavaScript でタブをブロックして IP を取得するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。