Laravel+Socket.io+Redis本地连接失败:ECONNREFUSED ::1:6379
Laravel实时Web应用搭建问题:Socket.io+Redis+Node.js Redis连接失败
问题背景
我基于Laravel搭建实时Web应用,采用Socket.io、Redis与Node.js服务架构,但启动Node服务后,客户端连接时出现Redis连接拒绝错误,无法正常实现实时消息推送。
相关代码
server.js(Node.js服务)
var app = require('express')(); app.use(function (req, res, next) { // Website you wish to allow to connect res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888'); // Request methods you wish to allow res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // Request headers you wish to allow res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // Set to true if you need the website to include cookies in the requests sent // to the API (e.g. in case you use sessions) res.setHeader('Access-Control-Allow-Credentials', true); // Pass to next layer of middleware next(); }); var server = require('http').Server(app); var io = require('socket.io')(server, { cors: { origin: '*' }, }); var redis = require('redis'); server.listen(3000, () => { console.log('hel'); }); io.on('connection', async function (socket) { console.log('client connected'); var redisClient = redis.createClient({ legacyMode: true, }); await redisClient.connect().catch(console.error); redisClient.subscribe('message'); redisClient.on('message', function (channel, data) { console.log('message received'); socket.emit(channel, data); }); socket.on('disconnect', function () { redisClient.quit(); }); });
Laravel控制器代码
public function store(Request $request, BaiDang $baiDang) { try { $baiDang->create($request->all()); if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $name = time() . rand(1, 100) . Str::random(40) . '.' . $file->extension(); Storage::putFileAs('files', $file, $name); $fileData['bai_dang_id'] = DB::table('bai_dang')->max('id'); $fileData['link'] = 'files/' . $name; FileBaiDang::create($fileData); } } Redis::connection(); Redis::publish('message', json_encode($request->all())); return $this->success($baiDang, 201, 'Created'); } catch (Exception $e) { //catch exception echo 'Message: ' . $e->getMessage(); return $this->error(400, 'Lỗi server update không thành công'); } }
客户端socket.io.js代码
import { io } from 'socket.io-client'; const socket_host = '127.0.0.1'; const socket_port = '3000'; const socket = io(socket_host + ':' + socket_port); socket.on('message', (data) => { console.log('aaahhahaahah'); });
已在app.js中导入:import './socket.io';
错误信息
执行node server启动Node服务后,客户端连接时输出:
client connected Error: connect ECONNREFUSED ::1:6379 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1300:16) { errno: -4078, code: 'ECONNREFUSED', syscall: 'connect', address: '::1', port: 6379 }
已尝试的排查
- 检查Redis服务状态,确认服务正在运行
- 核对Redis主机与端口配置,默认6379端口未修改
- 尝试过多种修复方案,问题仍未解决
解决方案
1. 强制Node.js使用IPv4连接Redis
错误显示Node尝试通过IPv6地址::1连接Redis,但Redis可能未监听IPv6。修改server.js中的Redis客户端配置,明确指定IPv4地址:
var redisClient = redis.createClient({ legacyMode: true, socket: { host: '127.0.0.1', // 强制使用IPv4 port: 6379 } });
2. 检查Redis监听配置
打开Redis配置文件(通常路径为/etc/redis/redis.conf),确认以下配置:
- 确保
bind指令包含127.0.0.1,或设置为bind 0.0.0.0(允许所有IPv4连接) - 测试环境下可设置
protected-mode no(生产环境需谨慎,建议通过其他方式限制访问)
修改完成后重启Redis服务:
sudo systemctl restart redis
3. 验证Redis连接
在终端执行以下命令,确认Redis可通过IPv4正常访问:
redis-cli -h 127.0.0.1 -p 6379 ping
如果返回PONG说明连接正常;若执行redis-cli -h ::1 -p 6379 ping失败,说明Redis确实未监听IPv6,此时通过步骤1的配置即可解决问题。
4. 优化Redis连接复用逻辑
当前代码在每个客户端连接时创建新的Redis客户端,频繁创建销毁连接会影响性能,建议全局复用一个Redis客户端:
// 全局创建Redis客户端,仅初始化一次 var redisClient = redis.createClient({ legacyMode: true, socket: { host: '127.0.0.1', port: 6379 } }); // 全局订阅频道,避免重复订阅 redisClient.connect().then(() => { redisClient.subscribe('message'); }).catch(console.error); // 全局监听消息,广播给所有连接的客户端 redisClient.on('message', function (channel, data) { console.log('message received'); io.emit(channel, data); // 广播给所有连接的socket }); io.on('connection', async function (socket) { console.log('client connected'); socket.on('disconnect', function () { // 无需关闭Redis连接,全局客户端供所有连接复用 }); });
内容的提问来源于stack exchange,提问作者Võ Khương Duy
相关产品推荐
相关产品推荐

