我想出了下面的解决方案。我留下了第二次更新以获得更多澄清。
我有一个用JavaScript编写的Discord机器人,使用discord. js库,我自己已经研究了将近两年。一年多前,我开始使用MySQL进行数据库查询等。这是在我本地的Windows 10机器上。由于当时这是一个小型爱好项目,我并不太担心只有一个MySQL实例用于开发和生产。最后,大约9个月前,我能够在运行Ubuntu 18.04的Linode服务器上启动并运行该机器人,以及运行在那里的MySQL数据库的副本。
到目前为止,通过这种设置,事情进展顺利。我使用WindowsPC上的本地数据库进行开发和测试,然后将更新推送到Linode上的Ubuntu 18.04服务器,其中包含生产数据库。此外,为了以防万一,我在开发时确实在PC本地运行机器人。有两个具有两个唯一令牌(一个用于生产,一个用于开发)的Disord机器人,因此我可以在更新时保持生产机器人运行。我没有像生产机器人那样全天候在服务器上运行开发机器人。
然而,最近,我的一个朋友(自称“for循环非凡”)开始帮助我进行开发。因此,我们认为现在是让开发数据库24/7全天候活跃的好时机,这样无论我是否在身边,他都可以在机器人上工作。这就是我们解决问题的地方。
我在下面留下了更新,因为我已经切换到mysql2
包以尝试找到解决方案。
所以,如果不是很明显的话,我的目标很简单:我希望我的机器人(当在我或我朋友的Windows机器上使用node. js本地运行时)连接到托管在我的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上的服务器时,它就是拒绝。我尝试了LinodeURL(example.com
)以及IP(LINODE.IP.ADDRESS.HERE
)地址,都给我同样的错误。我也知道Node的mysql2
包存在,我只是还没有切换。如果切换实际上有助于解决这个问题,请告诉我。
我已经尝试了这个网站上多个类似问题的多个答案,比如这个和这个,但是没有一个解决方案有效(包括添加socket ketPath
或更改port
等)
我尝试将mysqld. cnf文件中的bind地址
更改为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开发新手,所以我不完全知道我在做什么,但是我在这里遵循了这个指南,但是替换了我需要的代码,最终导致了一个完全独立的SSH连接错误。如果SSH绝对需要完成我想要的,那么请告诉我,我会就此提出一个新的问题。我只想在这里提到它,以表明我至少尝试过。
我已经切换到使用mysql2
,虽然错误消息更干净,但它仍然存在。
我尝试了Archil的解决方案,虽然现在我已经切换到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
,我将继续尝试不同的解决方案。
经过进一步研究,我发现权限没有像我想象的那样为我试图连接到服务器的用户设置。一旦我修复了这个问题,它确实连接了,但是机器人启动时查询的一个表显示为空。原来它不存在!
我已经制作了一个生产数据库的副本作为新开发数据库的基础。问题是,它缺少本地(旧)开发数据库中的一个表。这让我相信机器人正在连接MySQL,但没有从数据库中读取任何内容。我添加了正确的表,它工作得很好!我在下面留下了一个更具体的步骤的解决方案,以防像我这样的新手Web开发人员找到此页面。感谢您的帮助!
我已经离开了第二次更新,我如何得到这个解决方案。
简而言之,将bind-address
设置为0.0.0.0
确实有效。如果您使用的是原始mysql
包,则需要遵循Archil的解决方案。如果您使用的是mysql2
并且仍然存在错误(或者Archil的答案不适用于mysql
),请确保您仔细检查您尝试使用以下方法连接的用户的权限:
SHOW GRANTS FOR 'user'@'%';
假设您尝试像我一样远程连接,如果没有,则需要创建一个带有“%”通配符的用户。
此时它应该连接,就像我一样,如果之后有任何错误,它可能与数据库本身中的表有关。
我已经回答https://stackoverflow.com/a/50547109/4089212
请检查。您需要更改mySQL的身份验证模式。
在我的例子中(mariadb),我已经设法将绑定地址更改为文件中的0.0.0.0:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
重新启动后,我设法连接到数据库:
service mysql restart
您可能需要在文件夹/etc/mysql/mariadb. conf.d/
中搜索要编辑的正确文件
只是寻找绑定地址(可能有一个IP地址,如127.0.0.1)