1. 前言
在学习 Node.js 开发的过程中,Express 框架无疑是最受欢迎的选择之一。
作为一名前端开发者,我决定深入学习后端技术,搭建一个完整的博客系统。
第一步自然是连接数据库,而我选择了连接远程服务器上的 MySQL 数据库,而不是在本地搭建环境。
这看似简单的一步,却让我遇到了各种各样的问题。
本文将记录我在连接远程 MySQL 数据库过程中遇到的各种坑,希望能帮助到同样遇到困难的开发者。
2. 如何连接
2.1 环境准备
首先,我们需要安装必要的依赖:
bash
npm install express mysql2 sequelize dotenv
2.2 配置文件
为了安全管理数据库连接信息,我创建了 .env
文件来存储敏感信息:
数据库配置
ini
DB_HOST=your_server_ip
DB_PORT=3306
DB_NAME=your_database_name
DB_USER=your_username
DB_PASSWORD=your_password
服务器配置
ini
PORT=3000
NODE_ENV=development
2.3 数据库连接配置
然后创建 config/database.js
文件:
javascript
const { Sequelize } = require('sequelize');
require('dotenv').config();
// 从环境变量获取数据库配置
const DB_HOST = process.env.DB_HOST || 'localhost';
const DB_PORT = process.env.DB_PORT || 3306;
const DB_NAME = process.env.DB_NAME || 'test_db';
const DB_USER = process.env.DB_USER || 'root';
const DB_PASSWORD = process.env.DB_PASSWORD || '';
// 创建 Sequelize 实例,连接到远程数据库
const sequelize = new Sequelize(
DB_NAME,
DB_USER,
DB_PASSWORD,
{
host: DB_HOST,
port: DB_PORT,
dialect: 'mysql',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
dialectOptions: {
timezone: '+08:00'
},
logging: process.env.NODE_ENV !== 'production' ? console.log : false
}
);
// 测试数据库连接
const testConnection = async () => {
try {
await sequelize.authenticate();
console.log('数据库连接成功!');
} catch (error) {
console.error('无法连接到数据库:', error);
}
};
module.exports = {
sequelize,
testConnection
};
2.4 在应用中使用
在主应用文件 app.js
中:
javascript
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const { sequelize, testConnection } = require('./config/database');
const app = express();
// 中间件
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// 测试数据库连接
testConnection();
// 路由
app.get('/', function (req, res) {
res.send('hello, express');
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});
3. 问题
在实际连接过程中,我遇到了各种各样的问题,下面逐一解决。
3.1 MySQL 用户权限问题
问题现象:
sql
Access denied for user ''@'localhost' (using password: YES)
解决方案: 在 MySQL 服务器上创建允许远程连接的用户:
sql
# 登录 MySQL
mysql -u root -p
# 查看用户权限
SELECT user, host FROM mysql.user WHERE user = 'yel_test';
# 如果用户不存在,创建新用户
CREATE USER 'yel_test'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON yel_test.* TO 'yel_test'@'%';
# 如果用户已存在但只允许本地连接,添加远程连接权限
GRANT ALL PRIVILEGES ON yel_test.* TO 'yel_test'@'%' IDENTIFIED BY '123456';
# 刷新权限
FLUSH PRIVILEGES;
3.2 MySQL 配置限制
问题现象:
shell
ConnectionError [SequelizeConnectionError]: connect ETIMEDOUT
解决方案 : 修改 MySQL 配置文件(通常是 /etc/my.cnf
),添加或修改 bind-address
设置:
查找配置文件
bash
# 查找主要配置文件
cat /etc/my.cnf | grep bind-address
# 如果上面没有结果,查看是否有包含的配置目录
cat /etc/my.cnf | grep "!includedir"
# 修改配置文件
vi /etc/my.cnf
如果使用 vi 但不熟悉:
-
按 i 进入插入模式
-
移动到 [mysqld] 部分下方
-
添加 bind-address = 0.0.0.0
-
按 Esc 退出插入模式
-
输入 :wq 保存并退出(或 :q! 不保存退出)
然后重启 MySQL 服务:
bash
systemctl restart mysqld
# 或
service mysqld restart
3.4 防火墙限制
问题现象:
无法连接到数据库,但可以 ping 通服务器。
解决方案:
检查并开放服务器防火墙的 MySQL 端口(默认 3306):
bash
# 查看防火墙规则
firewall-cmd --list-all | grep 3306
# 如果没有开放,添加规则
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload
3.5 云服务提供商安全组设置
问题现象:
即使服务器防火墙已经开放端口,仍然无法连接。
解决方案:
在云服务提供商的控制面板中,确保安全组规则允许 3306 端口的入站流量:
允许 | MySQL 访问 | TCP:3306/3306 | IPv4 | 任何位置 (0.0.0.0/0)
3.6 VPN 导致的连接问题
问题现象:
即使所有配置都正确,仍然出现 ETIMEDOUT
错误。
解决方案:
关闭 VPN。VPN 可能会导致网络路由冲突,使得到数据库服务器的流量被错误地路由。
VPN 导致连接失败的原因包括:
- 网络路由冲突
- VPN 安全策略限制
- VPN 网络延迟
- DNS 解析问题
4. 总结
连接远程 MySQL 数据库看似简单,实际上涉及多个层面的配置:
-
应用层面:正确配置连接参数、环境变量和错误处理
-
数据库层面:用户权限、MySQL 配置
-
服务器层面:防火墙设置、端口开放
-
网络层面:安全组规则、VPN 设置、网络路由