2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「ネットワークが遅いんですけど」の問い合わせを改善する

Last updated at Posted at 2025-10-25

ネットワーク不具合の問い合わせの改善

組織内のネットワーク運用をしていると,よく「今日はネットワーク遅いですけど,なんかありますか?」とか「昨日遅かったけどなんかありました?」の問い合わせがあります.ユーザーからの不具合報告はありがたいのですが,主観的に遅いと言われても事象の確認ができなかったり,過去の事象を問い合わせられても確認が難しく,そのまま確認できずに終わることも多いです.
そこで,問い合わせに客観的な情報を含めてもらうことができれば,利用者は報告し易く,管理者も症状の確認に必要な情報が得られてお互いハッピーになれるのでは!?とサイトの応答時間を計測するページをcopilotと一緒に考えてみました.

日頃からサービスの応答時間を計測して,基準をもっておき,そこから明かに外れた値になっているときは問い合わせをしてもらいましょう.

アイデア

ほとんどのユーザーはwebブラウザを使っているので,ブラウザでネットワークが遅いに関連する情報が取得できればよさそう.また結果をクリップボードにコピーできれば便利.

実装

copilotに手伝ってもらいながら,指定したURLにアクセスして,そのコンテンツのダウンロードにかかった時間を測定するページを作ってみました.
結果もクリップボードへコピーするのと,計測した時刻の情報もあると嬉しいので,測定時刻も表示するようにしてみました.

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>応答時間測定</title>
</head>
<body>
  <h1>複数サイトの応答時間測定</h1>
  <p>このページは,ネットワークが遅いと感じる際に実際にいくつかのサイトへの接続時間がどのくらいかを測定し,また測定した環境についての情報を表示します.<br>
  ネットの不調を感じたときにはこのページで<strong>測定した結果をクリップボードにコピーし,その情報を含めて</strong>連絡していただけると,大変助かります.</p>
  <p id="timestamp">測定時刻: </p>
  <ul id="results"></ul>

  <h2>接続環境情報</h2>
  <pre id="platform"></pre>

  <button onclick="copyResults()">結果をクリップボードにコピー</button>

  <script>
    const sites = [
      { name: "Google", url: "https://www.google.co.jp/favicon.ico" },
      { name: "Yahoo! Japan", url: "https://www.yahoo.co.jp/favicon.ico" },
      { name: "Cloudflare", url: "https://www.cloudflare.com/favicon.ico" },
      { name: "Teams", url: "https://teams.microsoft.com/favicon.ico" },
      { name: "Zoom", url: "https://zoom.us/favicon.ico" }
    ];

    let resultText = "";

    function measureSite(site) {
      const startTime = performance.now();
      const img = new Image();

      img.onload = function() {
        const endTime = performance.now();
        const duration = Math.round(endTime - startTime);
        const text = `${site.name}: ${duration} ms`;
        displayResult(text);
        resultText += text + "\n";
      };

      img.onerror = function() {
        const text = `${site.name}: 接続失敗`;
        displayResult(text);
        resultText += text + "\n";
      };

      img.src = site.url + "?" + new Date().getTime();
    }

    function displayResult(text) {
      const li = document.createElement("li");
      li.textContent = text;
      document.getElementById("results").appendChild(li);
    }

    function getPlatform() {
      const platform = navigator.platform;
      const useragent= navigator.userAgent;
      const hardwareconcurrency = navigator.hardwareConcurrency;
      const devicememory = navigator.deviceMemory;
      document.getElementById("platform").textContent = "platform: " + platform + "\n" + "userAgent: " + useragent + "\n";
      document.getElementById("platform").textContent += "CPU core: " + hardwareconcurrency + "\n" + "Memory: " + devicememory;
      resultText += "\n動作環境:\n" + "platform: " + platform + "\n";
      resultText += "userAgent: " + useragent + "\n";
      resultText += "CPU core: " + hardwareconcurrency + "\n";
      resultText += "Memory: " + devicememory + "\n";
    }

    function copyResults() {
      navigator.clipboard.writeText(resultText)
        .then(() => alert("結果をクリップボードにコピーしました。"))
        .catch(() => alert("コピーに失敗しました。"));
    }

    window.onload = function() {
      const now = new Date();
      const timestamp = now.toLocaleString();
      document.getElementById("timestamp").textContent = "測定時刻: " + timestamp;
      resultText += "測定時刻: " + timestamp + "\n\n";
      sites.forEach(measureSite);
      getPlatform();
    };
  </script>
</body>
</html>

このファイルを保存して,開けばsitesに保存されているURLにアクセスし,コンテンツ取得にかかった時間を表示します.内部にサーバがあればそこに置いてもよいですし,ファイルサーバに置いても使えるとおもいます.

sitesのURLには,切り分け用に外部サイト以外にも内部サイトのURLも含めるのがお勧めです.他にも実際にアクセスが遅いと問い合わせがあるサービスがあればそのURLも含めてみるのもよいかとおもいます.ただし,計測しているのはfaviconをダウンロードする時間なので,サービスそのものへのアクセス時間ではないことには注意してください.

改良

これでも十分なのですが,こちらの環境だとロードバランサ経由で複数のhttp proxyを介して外部と接続しているので,実際にどのProxyサーバ経由でアクセスしているのかという情報も取得したいという要求がありました.
Proxyサーバがグローバルアドレスを持ち,NATされずに外部と通信しているなら,外部のサーバにアクセスしてきたIPやヘッダ情報を確認すればよいので,Azureのサービスでnode.jsのアプリを動かし,http proxy経由で接続してきたクライアントの情報をjsonで返すようにし,htmlの中で返されたjsonの値を表示するように改良しました.これもcopilotと相談して作ったコードになります.

この改良版は外部でサービスを動かす必要があるので,お手軽さがなくなります.必要な人のみどうぞ.

server.js
const express = require('express');
const app = express();

app.get('/info', (req, res) => {
  const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
  const proxyInfo = {
    ip: clientIp,
    x_forwarded_for: req.headers['x-forwarded-for'] || null,
    via: req.headers['via'] || null,
    user_agent: req.headers['user-agent'] || null
  };
  res.json(proxyInfo);
});

const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

測定ページへの追加

    function fetchEnvInfo() {
      fetch("https://nodejsを動かしている外部のURL")
        .then(response => response.json())
        .then(data => {
          const envText = JSON.stringify(data, null, 2);
          document.getElementById("env").textContent = envText;
          resultText += "\n接続環境情報:\n" + envText;
        })
        .catch(error => {
          const errorText = "環境情報の取得に失敗しました。";
          document.getElementById("env").textContent = errorText;
          resultText += "\n" + errorText + "\n";
        });
    }

あとこのfetchEnvInfo()を呼び出すためにhtml中のgetPlatform()の前後にfetchEnvInfo()を追加しておきます.

これで利用しているproxyの情報も得られるようになりました.

その他

ネットが遅い場合に,インターネットで公開されているスピード計測サイトで計測することもあるとおもいますが,問題を切り分けるためにイントラネットにも計測サイトが欲しいことがあります.
計測サイトを自前で用意したい場合は,librespeedソースコードを公開しているので,これを利用しましょう.
librespeedだとクライアントのIPも表示してくれるので,これもとてもありがたいです.
#Javascript単独では,自身が利用しているIPを確認することはできなさそうなので..

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?