You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过Apache和Express无法连接前端socket.io-client与后端socket.io

问题:线上环境Socket.IO前后端无法通信(本地正常)

后端基于LAMP栈+Express处理Webhook,Webhook接收正常,但前端Vue使用socket.io-client无法和后端Socket.IO建立连接,本地环境完全正常,线上出现异常。已配置Apache ProxyPass但缺少关键配置项。


前端Vue代码

import { createApp } from 'vue';
import { io } from "socket.io-client";

import VueSocketIOExt from 'vue-socket.io-extended';
import OysterApp from '../views/OysterApp.vue';

export default function loadApp(el, pinia) {
    const app = createApp(OysterApp);

    if(pinia){
        app.use(pinia);
    }
    
    // 尝试初始化socket连接
    try{
        const socket = io("http://localhost:8080", {
            reconnection: true,
            rejectUnauthorized: false,
            transports: [ "websocket", "polling"],
        });

        socket.on("connect_error", (err) => {
            console.log(err);
            console.log(err.description);
            console.log(err.context);
        });

        socket.on('connect', function(socket) { 
            console.log('Connected!');
        });

        console.log(socket);
        app.use(VueSocketIOExt, socket);
    } catch(e){
        console.log(e)
    }

    app.mount(el);
}

后端Express代码

'use strict'

const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors');

const app = express()

app.use(bodyParser.json())

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Headers", "Content-Type");
    res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
    next();
});

app.use(cors({
    origin: 'http://localhost:8080'
}));

const server = app.listen(8080, function (err) {
    if (err) {
        throw err;
    } else {
        console.log('Server started on port 8080')
    }   
})

try{
    const io = require('socket.io')(server, { cors: {}});
    app.set('io', io); 

    io.on("connection_error", (err) => {
        console.log(err.req);
        console.log(err.code);
        console.log(err.message);
        console.log(err.context);
    });
    
    // 处理webhook请求
    app.post('/webhook', function (req, res, next) {
        const io = req.app.get('io');

        console.log('hit endpoint', req.body)
        io.sockets.emit('catalogUpdated', req.body)

        res.sendStatus( 200 );
        next();
    })
    
    // 浏览器刷新时该回调永远不触发,是核心问题
    io.on('connection', function(socket){   
        console.log('A connection is made', socket); 
    });

    console.log(io);
} catch(err){
    console.log(err);
}

当前Apache虚拟主机配置

RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://localhost:8080/$1" [P,L] <-- 不确定这段重写是否需要

ProxyPreserveHost On
ProxyTimeout 60
ProxyPass /webhook http://localhost:8080/webhook <-- 确认有效
ProxyPassReverse /webhook http://localhost:8080/webhook <-- 不确定是否需要或配置正确

解决方案

1. 修正前端Socket连接地址

线上环境不能硬写http://localhost:8080,改用相对路径自动匹配当前域名:

const socket = io("/", {
    reconnection: true,
    rejectUnauthorized: false,
    transports: ["websocket", "polling"],
});

2. 完善Apache代理配置

需要为Socket.IO的全路径(包括握手、轮询、WebSocket升级)配置代理,替换原有配置:

RewriteEngine On

# WebSocket连接升级代理
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]

# HTTP请求代理(适配Socket.IO轮询、握手)
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:8080/$1 [P,L]

ProxyPreserveHost On
ProxyTimeout 300 # 延长超时时间,适配WebSocket长连接
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/

# 若需保留LAMP原有路径(如/phpmyadmin),添加排除规则:
# RewriteCond %{REQUEST_URI} !^/phpmyadmin
# RewriteCond %{REQUEST_URI} !^/your-lamp-path

3. 修复后端CORS配置

线上环境需允许当前网站域名,而非localhost:8080:

// Express CORS配置
app.use(cors({
    origin: 'https://your-production-domain.com', // 替换为你的线上域名
    credentials: true // 若需携带Cookie等凭证则开启
}));

// Socket.IO CORS配置同步修改
const io = require('socket.io')(server, { 
    cors: {
        origin: 'https://your-production-domain.com',
        credentials: true
    }
});

4. 检查服务器防火墙/安全组

确保线上服务器的8080端口未被拦截,或仅开放80/443端口(流量通过Apache转发)。

5. 排查前端错误信息

打开浏览器控制台,查看connect_error的具体错误(如CORS问题、路径错误、超时),针对性调整配置。


内容的提问来源于stack exchange,提问作者Trevor Miles Wagner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:00:56