TL;DR
大家好,
我试图从用 Express 编写的 NodeJS 前端调用 NodeJS 后端微服务,通过Consul https://www.consul.io DNS接口 https://www.consul.io/intro/getting-started/services.html#querying-services但我有错误。
我正在使用Node.js 域名解析 API https://nodejs.org/api/dns.html为唯一节点应用程序设置 dns,以便对本地 Consul DNS 接口进行后续 dns.resolve() 调用。
Target
我希望能够向我的后端服务发出 http 请求,而无需在客户端代码中连接其 IP 和端口。我也不想编写自定义代码来查询 Consul HTTP API,以便在需要调用服务时获取 ip:port 对。
Problem
问题是当我使用axios https://www.npmjs.com/package/axios(如同request https://www.npmjs.com/package/request)对后端服务进行 HTTP 调用时,我总是收到错误,因为它无法解析地址。看来 Axios 没有使用我之前设置的 dns:
dns.setServers(['127.0.0.1:8600']);
Update_1
使用 consul 的 -recursor 命令行选项将虚拟机 (/etc/resolv.conf) 的 dns 设置为 localhost e,并使用默认 dns 一切正常!我仍然想了解我只在我的 Node.js 应用程序上设置 dns 时做错了什么。
Setup
- 1 个 FE 节点,带有一个 Nodejs 进程,运行一个带有 Express Js 的简单 Web 服务器。在 app.get('/') 路由中,它通过 consul 和 axios 对名为 be01 的后端服务进行 REST POST 调用(如 request)。
- 2 BE 节点,带有一个 nodejs 进程,运行一个简单的 Web 服务器,并使用 Expressjs 公开 REST api。
- 1 个 Consul 节点,Consul 作为服务器运行。
- 每个节点都有自己的 consul 代理运行并加入到集群中。
- TCP 端口已正确打开
This are the servers:
![enter image description here](https://i.stack.imgur.com/FSTdd.png)
This is from the Consul UI:
![enter image description here](https://i.stack.imgur.com/V3FR6.png)
在 FE 节点上运行 consul 成员我得到:
agent-server 10.0.1.7:8301 alive server 1.0.1 2 dc1 <all>
agent-be-01 10.0.1.5:8301 alive client 1.0.1 2 dc1 <default>
agent-be-02 10.0.1.6:8301 alive client 1.0.1 2 dc1 <default>
agent-fe 10.0.1.4:8301 alive client 1.0.1 2 dc1 <default>
如果我跑挖@localhost -p 8600 be01.service.consul SRV在 FE 节点上我正确地得到了这个结果(如领事文档中所示 https://www.consul.io/intro/getting-started/services.html#querying-services):
root@NGINXLB:~/node8080$ dig @localhost -p 8600 be01.service.consul SRV
; <<>> DiG 9.9.5-3ubuntu0.16-Ubuntu <<>> @localhost -p 8600 be01.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43367
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 5
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;be01.service.consul. IN SRV
;; ANSWER SECTION:
be01.service.consul. 0 IN SRV 1 1 8081 agent-be-02.node.dc1.consul.
be01.service.consul. 0 IN SRV 1 1 8080 agent-be-01.node.dc1.consul.
;; ADDITIONAL SECTION:
agent-be-02.node.dc1.consul. 0 IN A 10.0.1.6
agent-be-02.node.dc1.consul. 0 IN TXT "consul-network-segment="
agent-be-01.node.dc1.consul. 0 IN A 10.0.1.5
agent-be-01.node.dc1.consul. 0 IN TXT "consul-network-segment="
;; Query time: 2 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Fri Dec 01 10:09:00 UTC 2017
;; MSG SIZE rcvd: 246
这是 BE 服务代码:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var jsonParser = bodyParser.json()
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.post('/api/getUserTiles', jsonParser, function (req, res) {
console.log("> API request for '/api/getUserTiles'");
if (!req.body) { return res.sendStatus(400) }
else {
var user = req.body.user;
console.log("User: " + user);
res.json({
"authorizedTiles": [
{"tileID": "profile"}
,{"tileID": "search"}
,{"tileID": "test"}
],
"email": "[email protected] /cdn-cgi/l/email-protection",
"userName":"Max",
"has_error": false,
"error_message": ""
});
}
});
var server = app.listen(8080, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
使用 ip:port 和 curl 从 FE 调用它不会出现任何问题:
root@NGINXLB:~/node8080$ curl -d="user=Max" -X POST http://10.0.1.5:8080/api/getUserTiles
{"authorizedTiles":[{"tileID":"profile"},{"tileID":"search"},{"tileID":"test"}],"email":"[email protected] /cdn-cgi/l/email-protection","userName":"Max","has_error":false,"error_message":""}
FE 节点上的 Web 服务简单来说是这样的:
var axios = require('axios');
var dns = require('dns');
var consul = require('consul')();
dns.setServers(['127.0.0.1:8600']);
//console.log(dns.getServers());
dns.resolveSrv("be01.service.consul", function(err, records){
console.log("\nDNS SRV query");
if(err){
console.log(err);
}else{
console.log(records);
}
});
consul.health.service({
"service": "be01",
"dc": "dc1",
"passing": true
}, function(err, result){
console.log("\nConsul.health.service query:");
if(err){console.log(err); throw err;}
else if(result.length > 0){
for(var i=0; i<result.length; i++){
console.log(result[i].Node.Address + ":" + result[i].Service.Port);
}
}
});
axios.post("http://be01.service.consul/api/getUserTiles", {'user':'Max'})
.then(function(response){
if (response.data.has_error) {
console.log("\nRESPONSE HAS ERROR!");
}else {
console.log("\nSUCCESS!");
}
})
.catch(function(err) {
console.log("\nERROR CALLING THE BE SERVICE");
});
运行它我得到以下结果:
root@NGINXLB:~/node8080$ node app.js
DNS SRV query
[ { name: 'agent-be-01.node.dc1.consul',
port: 8080,
priority: 1,
weight: 1 },
{ name: 'agent-be-02.node.dc1.consul',
port: 8081,
priority: 1,
weight: 1 } ]
Consul.health.service query:
10.0.1.5:8080
10.0.1.6:8081
ERROR CALLING THE BE SERVICE
{ Error: getaddrinfo ENOTFOUND be01.service.consul be01.service.consul:80
at errnoException (dns.js:50:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'be01.service.consul',
host: 'be01.service.consul',
port: 80,
...
...
结论
正如您所看到的,nodejs 客户端正在调用 be 服务,但尝试解析“be01.service.consul”失败。此外,它使用端口 80,而不是 Consul DNS 接口提供的 8080 或 8081。我缺少什么?