使用Consul DNS+request包调用服务时出现ENOTFOUND错误求助
我之前在做服务间通信时碰到过几乎一模一样的问题,结合你的代码和报错信息,咱们一步步拆解解决:
先排查DNS配置的格式问题
你当前写的dns.setServers([ ${config.consul.host}:8600 ])格式有问题——Node.js的dns.setServers()要求传入的服务器地址必须符合RFC 5952规范,UDP协议的地址需要加上udp://前缀(如果不加协议,Node会默认识别为无效地址,直接 fallback到系统DNS,这就是为什么你本地dig能解析但Node里不行)。
修正后的配置应该是:
dns.setServers([ `udp://${config.consul.host}:8600` ]);
注意:
config.consul.host最好直接用Consul服务器的IP地址,如果是域名的话,这个域名本身还需要被解析,反而会引入额外的不确定性。
先验证Node.js的DNS解析是否正常
先写一段独立代码测试DNS解析是否生效,排除request包的干扰:
const dns = require('dns'); // 替换成你的Consul实际地址 dns.setServers(['udp://192.168.1.100:8600']); // 解析A记录(获取服务IP) dns.resolve4('auth.service.consul', (err, addresses) => { console.log('A记录解析结果:', err, addresses); }); // 解析SRV记录(Consul服务发现的标准方式,能获取服务端口) dns.resolveSrv('_http._tcp.auth.service.consul', (err, records) => { console.log('SRV记录解析结果:', err, records); });
如果这段代码能输出正确的IP和SRV记录,说明DNS配置没问题;如果还是报错,那要检查Consul的DNS服务是否开放UDP请求、防火墙是否放行8600端口,以及Consul里的auth服务是否健康注册。
让request包正确使用Consul DNS的正规方案
如果DNS解析正常,但request还是报错,大概率是因为旧版本的request底层HTTP客户端没有正确复用Node.js的DNS设置。这里有两种靠谱的解法:
解法1:手动解析DNS后发起请求
先通过Node.js的dns模块解析Consul的SRV/A记录,再把解析后的IP+端口拼到请求地址里,彻底绕开request的默认DNS逻辑:
const dns = require('dns'); const request = require('request'); // 先解析SRV记录(拿到服务端口和目标主机) dns.resolveSrv('_http._tcp.auth.service.consul', (srvErr, srvRecords) => { if (srvErr) throw srvErr; // 这里可以加负载均衡逻辑,比如随机选一个SRV记录 const targetSrv = srvRecords[0]; // 再解析目标主机的A记录(拿到服务IP) dns.resolve4(targetSrv.name, (aErr, addresses) => { if (aErr) throw aErr; const serviceIp = addresses[0]; // 构造正确的请求参数 const options = { baseUrl: `http://${serviceIp}:${targetSrv.port}`, json: { '': '' }, headers: { authorization: '' } }; // 发起请求 request.post(req.path, options, (error, response, body) => { if (error) throw error; res.status(response.statusCode).json(body); }); }); });
解法2:用自定义Agent强制DNS解析
通过自定义http.Agent的lookup方法,强制request使用我们配置的DNS服务器来解析域名:
const dns = require('dns'); const http = require('http'); const request = require('request'); // 配置自定义Agent,指定lookup方法使用我们的DNS设置 const customAgent = new http.Agent({ lookup: (hostname, options, callback) => { dns.lookup(hostname, options, callback); } }); // 请求参数中加入自定义Agent const options = { baseUrl: `http://auth.service.consul`, json: { '': '' }, headers: { authorization: '' }, agent: customAgent }; // 发起请求 request.post(req.path, options, (error, response, body) => { if (error) throw error; res.status(response.statusCode).json(body); });
额外小建议
如果长期需要和Consul做服务发现,也可以考虑用专门的consul npm包,直接通过Consul的HTTP API获取服务地址——这种方式比DNS更灵活,也更容易排查问题。当然如果一定要用DNS方式,上面的两种解法都能解决你的问题。
内容的提问来源于stack exchange,提问作者joshk132

