当尝试通过docker-compose将NodeJS应用连接到MySQL镜像时出现ECONNREFUSED错误。
当尝试通过docker-compose将NodeJS应用连接到MySQL镜像时出现ECONNREFUSED错误。
我有一个项目,使用NodeJS作为服务器(使用ExpressJS),并使用MySQL处理数据库。为了将它们同时加载,我正在使用Docker。尽管该项目包括一个ReactJS客户端(我有一个用于React的客户端文件夹和一个用于NodeJS的服务器文件夹),但我已经测试了服务器和客户端之间的通信,它可以正常工作。以下是与server
和mysql
服务相关的代码:
docker-compose.yml
mysql:
image: mysql:5.7
environment:
MYSQL_HOST: localhost
MYSQL_DATABASE: sampledb
MYSQL_USER: gfcf14
MYSQL_PASSWORD: xxxx
MYSQL_ROOT_PASSWORD: root
ports:
- 3307:3306
restart: unless-stopped
volumes:
- /var/lib/mysql
- ./db/greendream.sql:/docker-entrypoint-initdb.d/greendream.sql
.
.
.
server:
build: ./server
depends_on:
- mysql
expose:
- 8000
environment:
API_HOST: "http://localhost:3000/"
APP_SERVER_PORT: 8000
ports:
- 8000:8000
volumes:
- ./server:/app
links:
- mysql
command: yarn start
然后是服务器的Dockerfile
:
FROM node:10-alpine RUN mkdir -p /app WORKDIR /app COPY package.json /app COPY yarn.lock /app RUN yarn install COPY . /app CMD ["yarn", "start"]
在服务器的package.json
中,脚本start
只是这样的:"start": "nodemon index.js"
执行的文件index.js
如下:
const express = require('express'); const cors = require('cors'); const mysql = require('mysql'); const app = express(); const con = mysql.createConnection({ host: 'localhost', user: 'gfcf14', password: 'xxxx', database: 'sampledb', }); app.use(cors()); app.listen(8000, () => { console.log('App server now listening on port 8000'); }); app.get('/test', (req, res) => { con.connect(err => { if (err) { res.send(err); } else { res.send(req.query); } }) });
所以现在我只想确认是否建立了连接。如果成功,我会将从前端获取的参数返回,看起来像这样:
axios.get('http://localhost:8000/test', { params: { test: 'hi', }, }).then((response) => { console.log(response.data); });
因此,在实现连接之前,我会在浏览器的控制台中得到{ test: 'hi' }
。我期望在连接成功后立即得到它,但实际上我得到的是这个:
{ address: "127.0.0.1" code: "ECONNREFUSED" errno: "ECONNREFUSED" fatal: true port: 3306 syscall: "connect" __proto__: Object }
我以为可能是我权限不对,但我也尝试使用root
作为用户名和密码,但结果相同。奇怪的是,如果我刷新页面,我不会得到ECONNREFUSED
,而是得到一个PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR
(带有fatal: false
)。如果我使用正确的凭据,为什么会发生这种情况?请告诉我是否发现了我可能忽略的问题。
问题出现的原因是在mysql.createConnection方法中没有提供正确的mysql主机地址。由于mysql有自己的容器和IP地址,所以需要将mysql主机外部化,并允许docker-compose将mysql服务名称(在本例中为mysql)解析为其内部IP地址。换句话说,nodejs服务器将连接到mysql容器的内部IP地址。
解决方法是在nodejs服务器中将mysql主机外部化:
const con = mysql.createConnection({ host: process.env.MYSQL_HOST_IP, ... });
在docker-compose中的服务器服务中添加以下内容:
environment:
MYSQL_HOST_IP: mysql #在docker-compose中mysql服务的名称,它将被解析为mysql容器的内部IP地址
另外,一开始似乎可以正常工作,但是如果刷新后会出现PROTOCOL_ENQUEUE_HANDSHAKE_TWICE错误。怀疑HANDSHAKE_TWICE错误是由于每次调用get路由时都会连接导致的,因此将其从.get中移除,并放在外面,就在.createConnection之后。当运行时,会出现PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR错误(因为添加了一个简单的mysql查询)。但奇怪的是,如果我在server / index.js中更改一些内容并刷新浏览器,它就可以正常工作。
将.createConnection更改为.createPool后,问题得到解决。
非常感谢,非常感谢。我不知道还能在哪里寻找答案,你的回答真的解决了我的问题。我花了很多时间寻找答案。再次感谢。