Node.js dns.resolve4()エラー解決ガイド:ENOTFOUND、EAI_AGAINの対処法

2025-05-27

主な機能と役割

  • コールバック関数
    dns.resolve4() を呼び出す際には、結果を受け取るためのコールバック関数を指定する必要があります。このコールバック関数は、通常2つの引数を受け取ります。
    • 1つ目の引数 (err): エラーが発生した場合、エラーオブジェクトが渡されます。成功した場合は null になります。
    • 2つ目の引数 (addresses): IPv4アドレスの配列が渡されます。一つのホスト名に対して複数のIPv4アドレスが関連付けられている場合があります。
  • 非同期処理
    dns.resolve4() は非同期的に動作します。これは、IPv4アドレスの検索処理がバックグラウンドで行われ、Node.jsのメインスレッドをブロックしないことを意味します。処理が完了すると、コールバック関数が呼び出され、結果(IPv4アドレスまたはエラー)が渡されます。
  • IPv4アドレスの検索
    指定されたホスト名に関連付けられているIPv4アドレスを取得します。IPv4アドレスは、インターネット上でデバイスを識別し、通信するために使用される32ビットのアドレスです(例: 192.168.1.1)。

基本的な使い方 (コード例)

const dns = require('node:dns');

const hostname = 'www.example.com';

dns.resolve4(hostname, (err, addresses) => {
  if (err) {
    console.error('IPv4アドレスの解決に失敗しました:', err);
    return;
  }
  console.log(`ホスト名 ${hostname} の IPv4 アドレス:`, addresses);
  // addresses は IPv4 アドレスの配列です (例: ['93.184.216.34'])
  addresses.forEach((address) => {
    console.log(`- ${address}`);
  });
});

console.log('IPv4アドレスの解決を試行中です...');
  1. const dns = require('node:dns');: dns モジュールをインポートして、その機能を利用できるようにします。
  2. const hostname = 'www.example.com';: 解決したいホスト名を定義します。
  3. dns.resolve4(hostname, (err, addresses) => { ... });: dns.resolve4() 関数を呼び出します。
    • 最初の引数には、解決したい hostname を渡します。
    • 2つ目の引数には、結果を受け取るためのコールバック関数を渡します。
  4. if (err) { ... }: コールバック関数内で、最初のエラー引数 err を確認します。エラーが存在する場合は、エラーメッセージを出力して処理を終了します。
  5. console.log(...): エラーがない場合、解決されたIPv4アドレスの配列 addresses を出力します。
  6. addresses.forEach(...): 配列内の各IPv4アドレスを個別に表示します。
  7. console.log('IPv4アドレスの解決を試行中です...');: dns.resolve4() は非同期処理なので、このメッセージは通常、IPv4アドレスの解決が完了する前に出力されます。


一般的なエラー

    • 原因
      指定されたホスト名 (<hostname>) がDNSサーバーで見つからなかった場合に発生します。ホスト名が間違っている、存在しない、またはDNSサーバーが正しく機能していない可能性があります。
    • トラブルシューティング
      • ホスト名の確認
        指定したホスト名にスペルミスがないか、正しいホスト名であることを確認してください。
      • インターネット接続の確認
        Node.jsを実行しているマシンがインターネットに接続されていることを確認してください。DNSルックアップはインターネットを通じて行われるため、接続がないと失敗します。
      • DNSサーバーの確認
        使用しているDNSサーバーが正常に機能しているか確認してください。他のウェブサイトにはアクセスできるのに特定のアドレスでエラーが出る場合は、そのホスト名に問題がある可能性が高いです。
      • 他のDNS解決ツールの使用
        ping コマンドや nslookup (Windows), dig (macOS/Linux) などのコマンドラインツールを使って、同じホスト名のIPアドレスを解決できるか試してみてください。これらのツールで解決できない場合は、Node.jsの問題ではなく、DNS自体の問題である可能性が高いです。
  1. Error: getaddrinfo EAI_AGAIN <hostname> (または同様のエラー)

    • 原因
      DNSサーバーが一時的に応答していない、またはビジー状態である場合に発生することがあります。これは一時的なネットワークの問題である可能性があります。
    • トラブルシューティング
      • 再試行
        しばらく待ってから再度 dns.resolve4() を実行してみてください。一時的な問題であれば、再試行で解決することがあります。
      • ネットワーク状況の確認
        ネットワークの遅延や不安定さがないか確認してください。
      • DNSサーバーの変更
        可能であれば、別のDNSサーバー(例えば、Google Public DNS: 8.8.8.8, Cloudflare DNS: 1.1.1.1 など)を使用するようにシステムの設定を変更してみるのも有効な場合があります。
  2. TypeError: callback must be a function

    • 原因
      dns.resolve4() 関数の第二引数として関数(コールバック関数)が渡されていない場合に発生します。
    • トラブルシューティング
      • コールバック関数の指定
        dns.resolve4() を呼び出す際に、必ずエラーと結果を受け取るためのコールバック関数を第二引数として渡してください。
  3. タイムアウト関連のエラー (まれ)

    • 原因
      DNSルックアップが指定された時間内に完了しなかった場合に発生する可能性があります。通常は、ネットワークの遅延が大きい場合や、DNSサーバーの応答が非常に遅い場合に起こりえます。
    • トラブルシューティング
      • ネットワーク状況の確認
        ネットワークの接続状況や速度を確認してください。
      • DNSサーバーの変更
        より応答性の高いDNSサーバーを使用するように変更してみてください。

トラブルシューティングの一般的なヒント

  • Node.jsのドキュメントを参照
    Node.jsの公式ドキュメントには、dns モジュールに関する詳細な情報が記載されています。
  • シンプルなコードでテスト
    問題を切り分けるために、できるだけシンプルなコードで dns.resolve4() の動作を確認してみてください。
  • ログ出力の活用
    エラーが発生した際の情報や、関連する変数の値をログに出力するようにして、問題の状況を把握しやすくします。
  • エラーメッセージをよく読む
    エラーメッセージは、問題の原因を特定するための重要な情報を含んでいます。


例1: 単一のホスト名のIPv4アドレスを取得する

これは最も基本的な使い方です。指定されたホスト名のIPv4アドレスを一つまたは複数取得し、コンソールに出力します。

const dns = require('node:dns');

const hostname = 'www.google.com';

dns.resolve4(hostname, (err, addresses) => {
  if (err) {
    console.error('IPv4アドレスの解決に失敗しました:', err);
    return;
  }
  console.log(`ホスト名 ${hostname} の IPv4 アドレス:`);
  addresses.forEach((address) => {
    console.log(`- ${address}`);
  });
});

console.log('IPv4アドレスの解決を試行中です...');

説明

  • 非同期処理の確認: 最後の console.log() は、resolve4() が非同期的に実行されるため、結果が表示される前に出力されることが多いです。
  • 結果の表示: addresses.forEach() で取得した各IPv4アドレスをコンソールに出力します。
  • エラーハンドリング: if (err) ブロックでエラーが発生した場合の処理を行います。
  • コールバック関数:
    • err: エラーが発生した場合、エラーオブジェクトが渡されます。成功した場合は null です。
    • addresses: ホスト名に関連付けられたIPv4アドレスの配列が渡されます。
  • dns.resolve4(hostname, (err, addresses) => { ... });: resolve4() 関数を呼び出し、ホスト名とコールバック関数を渡します。
  • hostname: 解決したいホスト名を文字列で定義します。
  • require('node:dns'): dns モジュールをインポートします。

例2: 複数のホスト名のIPv4アドレスを順に取得する

複数のホスト名のIPv4アドレスを順番に取得し、それぞれの結果を表示する例です。

const dns = require('node:dns');

const hostnames = ['www.example.com', 'nodejs.org', 'www.github.com'];

async function resolveHosts() {
  for (const hostname of hostnames) {
    try {
      const addresses = await new Promise((resolve, reject) => {
        dns.resolve4(hostname, (err, addresses) => {
          if (err) {
            reject(err);
            return;
          }
          resolve(addresses);
        });
      });
      console.log(`ホスト名 ${hostname} の IPv4 アドレス:`, addresses);
    } catch (err) {
      console.error(`ホスト名 ${hostname} の解決に失敗しました:`, err);
    }
  }
}

resolveHosts();
console.log('ホスト名の解決を試行中です...');

説明

  • await: Promise が解決されるまで処理を一時停止し、結果を取得します。
  • try...catch: Promise が reject された場合(エラーが発生した場合)の処理を行います。
  • new Promise(...): dns.resolve4() のコールバック形式を Promise ベースの非同期処理に変換します。これにより、async/await を使用してより直感的に非同期処理を記述できます。
  • for...of ループ: ホスト名の配列を順番に処理します。
  • async function resolveHosts(): 非同期処理を扱うための async 関数を定義します。
  • hostnames: 解決したいホスト名の配列を定義します。

例3: エラーハンドリングと特定のIPv4アドレス数の処理

特定の数のIPv4アドレスが解決された場合にのみ処理を行う例です。

const dns = require('node:dns');

const hostname = 'www.cloudflare.com'; // 複数のIPv4アドレスを持つ可能性のあるホスト

dns.resolve4(hostname, (err, addresses) => {
  if (err) {
    console.error('IPv4アドレスの解決に失敗しました:', err);
    return;
  }

  console.log(`ホスト名 ${hostname} の IPv4 アドレス:`, addresses);

  if (addresses.length >= 2) {
    console.log('少なくとも2つのIPv4アドレスが見つかりました。');
    // ここで2つ以上のアドレスに対する処理を行う
  } else {
    console.log('見つかったIPv4アドレスは2つ未満です。');
  }
});

console.log('IPv4アドレスの解決を試行中です...');

説明

  • この例では、解決されたIPv4アドレスの配列の長さをチェックし、特定の数以上のアドレスが見つかった場合に特別な処理を行います。

例4: エラーの種類による異なる処理

エラーの種類に応じて異なるメッセージを表示する例です。

const dns = require('node:dns');

const hostname = 'invalid-hostname-that-does-not-exist.example';

dns.resolve4(hostname, (err, addresses) => {
  if (err) {
    if (err.code === 'ENOTFOUND') {
      console.error(`エラー: ホスト名 "${hostname}" は見つかりませんでした。`);
    } else if (err.code === 'EAI_AGAIN') {
      console.error(`エラー: ホスト名 "${hostname}" の解決を再試行してください (一時的な問題かもしれません)。`);
    } else {
      console.error('予期しないエラーが発生しました:', err);
    }
    return;
  }
  console.log(`ホスト名 ${hostname} の IPv4 アドレス:`, addresses);
});

console.log('IPv4アドレスの解決を試行中です...');
  • エラーオブジェクト err には code プロパティが含まれており、エラーの種類を示す文字列が入っています。この例では、ENOTFOUND (ホストが見つからない) と EAI_AGAIN (一時的なDNS解決エラー) を区別して処理しています。


dns.promises.resolve4() (PromiseベースのAPI)

Node.jsの dns モジュールには、PromiseベースのAPIも用意されています。これにより、async/await 構文を使用して、よりモダンで読みやすい非同期コードを書くことができます。

const dns = require('node:dns').promises;

async function getIPv4Addresses(hostname) {
  try {
    const addresses = await dns.resolve4(hostname);
    console.log(`ホスト名 ${hostname} の IPv4 アドレス:`, addresses);
    return addresses;
  } catch (err) {
    console.error(`ホスト名 ${hostname} の解決に失敗しました:`, err);
    return null;
  }
}

async function main() {
  await getIPv4Addresses('www.example.com');
  await getIPv4Addresses('nodejs.org');
}

main();
console.log('IPv4アドレスの解決を試行中です...');

説明

  • try...catch: エラーハンドリングも Promise の仕組みに合わせて記述できます。
  • await dns.resolve4(hostname): dns.resolve4() が返す Promise を await することで、解決が完了するまで処理を一時停止し、結果を同期的なスタイルで取得できます。
  • async function getIPv4Addresses(hostname): 非同期関数を定義します。
  • require('node:dns').promises: dns モジュールの Promise API をインポートします。

利点

  • Promise の then()catch() を使ったより複雑な非同期処理の制御も可能です。
  • async/await を使用することで、非同期処理が同期的なコードのように見えるため、理解しやすく、記述も容易になります。

dns.lookup() (より低レベルなAPI)

const dns = require('node:dns');

const hostname = 'www.example.com';

dns.lookup(hostname, (err, address, family) => {
  if (err) {
    console.error(`ホスト名 ${hostname} のルックアップに失敗しました:`, err);
    return;
  }
  console.log(`ホスト名 ${hostname} の IP アドレス: ${address}, ファミリー: IPv${family}`);
});

console.log('ホスト名のルックアップを試行中です...');

説明

  • family: IPv4 の場合は 4、IPv6 の場合は 6 が返されます。
  • dns.lookup(hostname, (err, address, family) => { ... });: コールバック関数は、エラー、解決されたIPアドレス (address)、そしてアドレスファミリー (family: 4 または 6) を受け取ります。

利点

  • より低レベルな制御が必要な場合に便利です。
  • IPv4 と IPv6 の両方に対応したアプリケーションを開発する場合に、どちらのアドレスが解決されたかを知ることができます。

欠点

  • dns.resolve4() のように複数のIPv4アドレスが関連付けられている場合でも、通常は最初に見つかった一つのアドレスしか返しません。すべてのアドレスを取得したい場合は、他の方法と組み合わせる必要があります。

dns.resolve() (汎用的なDNSレコード解決)

dns.resolve() 関数は、特定のタイプのDNSレコード(A, AAAA, MX, TXT, SRV など)を解決するための汎用的な関数です。IPv4アドレスを取得する場合は、レコードタイプとして 'A' を指定します。

const dns = require('node:dns');

const hostname = 'www.example.com';

dns.resolve(hostname, 'A', (err, addresses) => {
  if (err) {
    console.error(`ホスト名 ${hostname} の A レコード解決に失敗しました:`, err);
    return;
  }
  console.log(`ホスト名 ${hostname} の IPv4 アドレス (A レコード):`, addresses);
});

console.log('A レコードの解決を試行中です...');

説明

  • コールバック関数の addresses は、IPv4アドレスの配列として返されます。
  • dns.resolve(hostname, 'A', (err, addresses) => { ... });: 第二引数に解決したいレコードのタイプ ('A' は IPv4 アドレスを意味します) を指定します。

利点

  • より柔軟なDNSクエリが可能です。
  • IPv4だけでなく、他の種類のDNSレコード(メールサーバーの情報、テキスト情報など)も取得できます。

外部のDNS解決ライブラリ

Node.jsのエコシステムには、より高度なDNS解決機能を提供するサードパーティのライブラリも存在します。これらのライブラリは、キャッシュ機能、タイムアウト設定、カスタムDNSサーバーの指定など、追加の機能を提供することがあります。


dnscache ライブラリ

const dns = require('node:dns');
const dnscache = require('dnscache')({
  enable: true,
  maxAge: 300, // キャッシュの有効期間 (秒)
  lookup: dns.lookup
});

const hostname = 'www.example.com';

dnscache.lookup(hostname, (err, address, family) => {
  if (err) {
    console.error(`ホスト名 ${hostname} のルックアップに失敗しました:`, err);
    return;
  }
  console.log(`ホスト名 ${hostname} の IP アドレス (キャッシュあり): ${address}, ファミリー: IPv${family}`);
});

console.log('キャッシュされたホスト名のルックアップを試行中です...');

説明

  • lookup オプションに Node.js の dns.lookup 関数を指定して使用します。
  • dnscache は、DNSルックアップの結果をキャッシュすることで、パフォーマンスを向上させるためのライブラリです。

利点

  • より高度なDNS関連の機能を利用できる場合があります。
  • DNSルックアップの結果をキャッシュすることで、同じホスト名の解決を何度も行う際の遅延を減らし、アプリケーションのパフォーマンスを向上させることができます。

dns.resolve4() はIPv4アドレスを簡単に取得できる便利な関数ですが、要件に応じて他の方法も検討できます。

  • 高度な機能 (キャッシュなど) が必要
    外部のDNS解決ライブラリ
  • 他のDNSレコードタイプも扱いたい
    dns.resolve()
  • IPv4/IPv6両対応や低レベルな制御
    dns.lookup()
  • モダンな非同期処理
    dns.promises.resolve4()