JavaScriptでブラウザのインターネット接続を判定する方法

2020.04.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Reactで構築しているWEBサイトにおいて、事前にインターネットの接続状態を判別させるケースがあり、JavaScriptでどのような実現方法があるのか調べました。先に結論を言いますと、Fetch APIやXHRを使用して公開ファイルへのアクセスを検証する方法が確実です。

NavigatorOnLine

window.navigator.onLineはブラウザのネットワーク接続状態を真偽値で返します。

if (window.navigator.onLine) {
  console.log("online");
} else {
  console.log("offline");
}

このAPIはブラウザによって挙動に違いがあります。また、次の説明文からインターネットの接続状態を判別するのには適さない事が分かりました。

Chrome および Safari は、ブラウザがローカルエリアネットワーク (LAN) またはルータに接続できないときにオフライン、それ以外の状況では true を返します。従って、false 値が返る場合はブラウザがオフラインであると考えることができますが、true 値は必ずインターネットにアクセスできると考えることはできません。仮想イーサネットアダプタを持つ仮想化ソフトウェアを実行しているコンピュータでは常に "接続中" になるなど、偽陽性になる可能性があります。

Firefox および Internet Explorer は、ブラウザをオフラインモードに切り替えると false 値を送信します。Firefox 41 まで、他の状態では true 値を返していました。Firefox 41 より OS X および Windows で、実際のネットワーク接続状態に従って値を返します。

引用元: window.navigator.onLine - Web API | MDN

Network Information API

window.navigator.connectionはネットワークの接続情報を返します。

console.log(window.navigator.connection.type);

次のいずれかの値がコンソールに出力されます。

説明
bluetooth Bluetooth接続
cellular セルラー接続(EDGE、HSPA、LTEなど)
ethernet イーサネット接続
none ネットワーク接続なし
mixed 複数の接続タイプを使用
other その他の接続タイプ
unknown 接続タイプの特定が不可
wifi Wi-Fi接続
wimax WiMAX接続

このAPIは接続タイプにより、ストリーミングサービスの帯域幅を調整するなど、幅広い用途に使えそうですが、現状ではIEやSafariに対応していません。

XMLHttpRequest

XMLHttpRequest(XHR)はHTTPリクエストを発行して、レスポンスを受け取ります。xhr.onerrorでネットワーク接続エラーを判別する事ができます。

const xhr = new XMLHttpRequest();

xhr.open("GET", "/favicon.ico");
xhr.send();

xhr.onload = () => {
  console.log(xhr.response);
};

xhr.onerror = () => {
  console.log("Network Error");
};

Fetch API

Fetch APIはXMLHttpRequestよりもシンプルにHTTPリクエストを発行できます。

fetch("/favicon.ico")
  .then(response => {
    console.log(response);
  })
  .catch(error => {
    console.log("Network Error");
  });

次のような関数でインターネットへの接続を判定するようにしました。

const checkOnline = async () => {
  const date = new Date();
  const timestamp = date.getTime();

  try {
    await fetch(`/favicon.ico?${timestamp}`);
  } catch {
    return false;
  }

  return true;
};

Fetch APIはIEが未対応なので、Polyfillを使うのが良いと思います。

github/fetch: A window.fetch JavaScript polyfill.

まとめ

ローカルエリアネットワーク(LAN)の接続確認はwindow.navigator.onLine、インターネットの接続確認にはFetch APIを使用するのが良いと思います。Fetch APIやXHRを使用する際には、キャッシュにも注意してみてください。

参考資料