如何使用ElasticSearch和Firebase解决“Error: connect ECONNREFUSED 127.0.0.1:9200”问题?

6

我知道这个问题已经被问了很多次,但是那些解决方案并不适用于我的情况。我使用以下两个命令启动了 ElasticSearchKibana

bin/elasticsearch
bin/kibana

服务器运行良好,使用浏览器访问 http://localhost:9200,我得到以下结果:

{
    "name" : "vg7RnLh",
    "cluster_name" : "elasticsearch",
    "cluster_uuid" : "gqDf0H67TxGZGYigAlu2mQ",
    "version" : {
        "number" : "6.1.2",
        "build_hash" : "5b1fea5",
        "build_date" : "2018-01-10T02:35:59.208Z",
        "build_snapshot" : false,
        "lucene_version" : "7.1.0",
        "minimum_wire_compatibility_version" : "5.6.0",
        "minimum_index_compatibility_version" : "5.0.0"
    },
    "tagline" : "You Know, for Search"
}

在使用 kibana 时一切都运行良好。这是我编写的 Firebase 云函数,如果有什么问题,我认为问题出在这里:
exports.downloadUserInfo = functions.https.onRequest((req, res) => {
    const { uid } = req.query;

    const searchConfig = {
        uri: 'http://localhost:9200/users/user/' + uid,
        method: 'GET'
    };

    request(searchConfig)
        .then((result) => {
           console.log(result);
           return res.status(200).send(result);
       })
           .catch((error) => {
               console.log(error);
               return res.status(400).send(error);
           });
});

request是通过yarn add request request-promise安装的模块。然后,在使用Postman测试API时,我收到了这个错误:

enter image description here

我该如何解决这个问题?

更新

我还在使用命令node app.js运行flashlight。当将新用户插入数据库时,新用户也会自动插入到ElasticSearch服务器(localhost)中,但是,当我尝试读取时,它会抛出请求错误。

第二次更新

这是创建用户的API:

exports.register = functions.https.onRequest((req, res) => {
    const { firstName, lastName } = req.body;

    admin.database().ref('users').push({ firstName, lastName })
        .then(() => res.status(201).send())
        .catch(() => res.status(400).send());
});

当使用此API创建新用户时,由于我正在使用flashlight插件,因此此用户将自动插入到我的本地ElasticSearch服务器中。但是,我不明白为什么当我尝试从同一服务器读取时,会出现请求错误。


你是否使用 firebase deploy 将此代码完全部署到云函数中运行? - Doug Stevenson
@DougStevenson 是的,部署成功了。 - K.Wu
3个回答

4

您的代码正在尝试访问本地主机:

uri: 'http://localhost:9200/users/user/' + uid,

这样是行不通的:您不能仅仅访问云函数所运行的容器中的“随机”端口。
我猜您在本地计算机上运行ElasticSearch,这就是“localhost”所指的内容。但是,在云函数环境中运行代码,您需要在可以公开访问的系统上运行ElasticSearch,并在“uri”中指定该计算机的IP地址。

谢谢您的回答。我忘了提到我也在运行“flashlight”插件,问题已经更新。 - K.Wu
抱歉,我不太清楚手电筒是什么,也不知道它与您的问题有什么关系。我只能告诉您的是,在部署的云函数中从本地主机发出请求是毫无意义的。 - Doug Stevenson
你不能在 Cloud Functions 上运行任意的 Node.js 程序(例如 ElasticSearch)。你需要提供自己的 Node.js 服务器,并在 uri 中连接该服务器的 IP 地址。 - Frank van Puffelen

2

Cloud Functions在由Google控制的服务器上运行,它们不在您的计算机上运行(除非您正在使用本地仿真进行测试)。

您的函数正在访问“localhost”上的URL:

const searchConfig = {
    uri: 'http://localhost:9200/users/user/' + uid,
    method: 'GET'
};

request(searchConfig).then(...)

在几乎所有情况下,localhost指的是IP地址127.0.0.1 - 即运行代码的同一台机器。当您的代码在Cloud Functions中运行时,这意味着localhost是运行您的代码的Google服务器实例。这绝对不是您想要的,不幸的是,您也无法访问运行在个人计算机上的服务。


谢谢您的回答。我忘了提到我也在运行“flashlight”插件,问题已经更新。 - K.Wu

1
这是答案。正如Frank van PuffelenDoug Stevenson所指出的,无论如何,我都不能从部署的Firebase函数执行任何对本地主机服务器的请求。
但是,在flashlight插件的帮助下,我可以让我的本地主机服务器知道我现在想执行搜索操作。我所做的是在flashlight文件夹内的config.js文件中:
exports.FB_REQ = 'search/request';
exports.FB_RES = 'search/response';

这两行代码的作用是告诉我的数据库在其中创建一个名为search的表,该表有两个子表,一个称为request,另一个称为responseflashlight将监视您的Firebase数据库并更新ES服务器中的任何数据,除了您写入search/request表中的内容。当您写入此表时,flashlight会检测到它,并知道您想立即执行搜索操作,然后在ES服务器上运行您放置在那里的查询,然后将结果存储在search/response表中,您只需侦听该表中的更新即可获得搜索结果。

新的downloadUserInfo API应该像这样:

exports.downloadUserInfo = functions.https.onRequest((req, res) => {
    const { uid } = req.query;

    const key = admin.database().ref('search/request')
        .push({ index: 'users', type: 'user', q: uid }).key;

    admin.database().ref(`search/response/${key}`).once('value')
        .then((snapshot) => {
            return res.status(200).send(snapshot.val());
        })
        .catch((error) => {
            return res.status(400).send(error);
        });
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接