【发布时间】:2021-04-18 20:08:33
【问题描述】:
我想出了下面的解决方案。我已经留下了第二次更新以获得更多说明。
上下文
我有一个 Discord 机器人,使用 discord.js 库用 JavaScript 编写,我自己已经开发了将近两年。一年多以前,我开始使用 MySQL 进行数据库查询等。这是在我的本地 Windows 10 机器上。由于当时这是一个小型业余项目,我并不太担心只有一个 MySQL 实例用于开发和生产。最后,大约 9 个月前,我能够在运行 Ubuntu 18.04 的 Linode 服务器上启动并运行机器人,并在其中运行 MySQL 数据库的副本。
到目前为止,通过此设置,一切顺利。我使用 Windows PC 上的本地数据库进行开发和测试,然后将更新推送到生产数据库所在的 Linode 上的 Ubuntu 18.04 服务器。此外,以防万一这有帮助,我在进行开发时会在我的 PC 上本地运行机器人。有两个 Discord 机器人,带有两个独特的令牌(一个用于生产,一个用于开发),因此我可以在进行更新时保持生产一个运行。我没有像生产机器人那样在服务器上 24/7 全天候运行开发机器人。
然而,最近,我的一个朋友(自称“for-loop extraordinaire”)开始帮助我进行开发。因此,我们认为现在是让开发数据库 24/7 全天候活动的好时机,这样无论我在不在,他都可以在机器人上工作。这就是我们要解决的问题。
问题
我已在下方留下更新,因为我已切换到 mysql2 包以尝试寻找解决方案。
所以,如果不是很明显,我的目标很简单:我希望我的机器人(当使用 node.js 在我或我朋友的 Windows 机器上本地运行时)连接到托管在我的 Ubuntu 18.04 服务器,在云中,而不是我的本地网络。我不怕承认我远非一个优秀的 Web 开发人员,所以我不知道后勤工作或这些东西如何真正运作的来龙去脉。我能走到这一步真是个奇迹。但我认为它会像连接到本地 MySQL 实例一样简单。但是,当我运行代码时,控制台会向我吐出这个错误。
Error: connect ECONNREFUSED LINODE.IP.ADDRESS.HERE:3306
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)
--------------------
at Protocol._enqueue (D:\Users\path\node_modules\mysql\lib\protocol\Protocol.js:144:48)
at Protocol.handshake (D:\Users\path\node_modules\mysql\lib\protocol\Protocol.js:51:23)
at Connection.connect (D:\Users\path\node_modules\mysql\lib\Connection.js:119:18)
at Object.<anonymous> (D:\Users\path\bot\index.js:118:5)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47 {
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: 'LINODE.IP.ADDRESS.HERE',
port: 3306,
fatal: true
}
这是我的代码当前的设置方式:
const mysql = require("mysql")
//CONNECT TO MYSQL
var con = mysql.createConnection({
host: 'example.com',
port: 3306,
user: 'user',
password: 'pass',
database: 'botDB',
charset: "utf8mb4"
});
//CONNECTED TO DATABASE
con.connect(err => {
if (err) { throw err };
console.log("My database is up and running!")
})
当host 是localhost(显然)时,此方法完美运行,但是当尝试远程连接到 Linode 上的服务器时,它只是拒绝。我已经尝试过 Linode URL (example.com) 和 IP (LINODE.IP.ADDRESS.HERE) 地址,都给了我同样的错误。我也知道 Node 的 mysql2 包存在,我只是还没有切换。如果切换确实有助于解决这个问题,请告诉我。
我尝试过的解决方案
我尝试了该网站上多个类似问题的多个答案,例如this one 和this,但是没有一个解决方案有效(包括添加socketPath 或更改port 等)
我尝试将mysqld.cnf 文件中的bind-address 更改为0.0.0.0 和*,这两者都允许机器人连接到数据库,但是仍然拒绝访问以实际读取数据库本身。我所知道的是它至少已连接(尽管现在再次尝试给我留下了一条错误消息)
code: 'ER_NOT_SUPPORTED_AUTH_MODE',
errno: 1251,
sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client',
sqlState: '08004',
fatal: true
MySQL 是最新的,所以这与我没有使用 mysql2 有关吗?无论如何,我不喜欢这个选项,但我想我至少会尝试一下。
我最后的办法是创建一个 SSH 隧道来连接到数据库。同样,我仍然是 Web 开发新手,所以我并不完全知道自己在做什么,但我关注了 this guide here,但替换了我需要的代码,并以完全独立的 SSH 连接错误告终。如果 SSH 是绝对需要来完成我想要的,那么请告诉我,我会就此提出一个新问题。我只是想在这里提及它以表明我至少尝试过。
更新
我已切换到使用mysql2,虽然错误消息更清晰,但它仍然存在。
我尝试过Archil's solution,虽然现在我切换到mysql2 并没有多大作用,但它确实让我对 MySQL 的身份验证系统有了更好的理解,这让我切换到了第一名。不幸的是,Archil 的回答和mysql2 升级都给了我同样的错误:
{
code: 'ER_ACCESS_DENIED_ERROR',
errno: 1045,
sqlState: '28000',
sqlMessage: "Access denied for user 'root'@'MY.LOCAL.IP.ADDRESS' (using password: YES)"
}
...尽管我已授予'root'@'%' 所有权限。
无论如何,这也不是我喜欢的方式。如果有更安全的解决方案,我很乐意接受。现在我已经安装了mysql2,我将继续尝试不同的解决方案。
更新 2
在进一步研究之后,我发现权限并没有像我认为的那样为我试图连接到服务器的用户设置。一旦我修复了它,它确实连接了,但是当机器人启动时被查询的表之一显示为空。原来它不存在!
我制作了一份生产数据库的副本,作为新开发数据库的基础。问题是,我的本地(旧)开发数据库中缺少 的表。这让我相信该机器人正在与 MySQL 连接,但没有从数据库中读取任何内容。我添加了正确的表格,效果很好!我在下面留下了一个包含更具体步骤的解决方案,以防其他像我这样的新手 Web 开发人员发现此页面。感谢您的帮助!
【问题讨论】:
-
您的服务器是在云端还是在本地网络上?
-
我假设 `host: 'example.com',` 也设置为正确的 IP?
-
@JairusMartin 我目前正在尝试连接的那个是在云中,是的。开发机器人在我的本地网络上。同样是的,对于
example.com,我已经尝试了 url 和 IP 本身(Linode 云服务器的),两者都具有相同的结果。我会更新我的帖子以进一步澄清这些。 -
@JustYourBud 此问题是否已解决或仍然存在?
-
@JustYourBud 如果我理解你的问题,可能是权限问题。您的云数据库端口应该是打开的。这肯定会解决您的问题。
标签: mysql node.js discord.js ubuntu-18.04 linode