socket.io服务器Transporterror

发布于 2025-01-25 20:13:15 字数 6995 浏览 3 评论 0原文

我正面临着socket.io服务器运行的问题的问题。

服务器发送错误,没有任何客户端。但是客户端可以从浏览器连接而无需任何问题...

这是服务器运行的控制台上的错误:

Socket error TransportError: xhr poll error
    at Polling.onError (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transport.js:46:37)
    at Request.<anonymous> (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:255:18)
    at Request.Emitter.emit (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/@socket.io/component-emitter/index.js:143:20)
    at Request.onError (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:356:14)
    at Timeout._onTimeout (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:329:30)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7) {
  description: 0,
  context: XMLHttpRequest {
    UNSENT: 0,
    OPENED: 1,
    HEADERS_RECEIVED: 2,
    LOADING: 3,
    DONE: 4,
    readyState: 4,
    onreadystatechange: [Function (anonymous)],
    responseText: 'Error: getaddrinfo ENOTFOUND undefined\n' +
      '    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26)',
    responseXML: '',
    status: 0,
    statusText: Error: getaddrinfo ENOTFOUND undefined
        at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26) {
      errno: -3008,
      code: 'ENOTFOUND',
      syscall: 'getaddrinfo',
      hostname: 'undefined'
    },
    open: [Function (anonymous)],
    setDisableHeaderCheck: [Function (anonymous)],
    setRequestHeader: [Function (anonymous)],
    getResponseHeader: [Function (anonymous)],
    getAllResponseHeaders: [Function (anonymous)],
    getRequestHeader: [Function (anonymous)],
    send: [Function (anonymous)],
    handleError: [Function (anonymous)],
    abort: [Function (anonymous)],
    addEventListener: [Function (anonymous)],
    removeEventListener: [Function (anonymous)],
    dispatchEvent: [Function (anonymous)]
  },
  type: 'TransportError'
}
  socket.io-client:manager reconnect attempt error +1ms
  socket.io-client:manager will wait 5000ms before reconnect attempt +0ms

要清楚,此错误不在客户端,而是在服务器上,浏览器的客户端具有工作连接服务器的错误。客户不会遇到任何错误,并且正常工作。

这是我的express.js服务器代码:

import express, {Express} from 'express';
import * as http from 'http';
import next, {NextApiHandler} from 'next';
import passport from 'passport';
import session, {SessionOptions} from 'express-session';
import {Options} from "session-file-store";
const FileStore = require('session-file-store')(session);
import uid from 'uid-safe';
import bodyParser from 'body-parser';
import routes from './routes';
import SocketServer from "../socketio/SocketServer";
import socketMiddleware from "../socketio/SocketMiddleware";

const port: number = parseInt(process.env.PORT || '3000', 10);
const dev: boolean = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler: NextApiHandler = nextApp.getRequestHandler();

nextApp.prepare().then(() => {
    const app: Express = express();
    const server: http.Server = http.createServer(app);

    // Socket io server
    const socketServer = new SocketServer(server);

    // Session
    const fileStoreOptions: Options = {
        path: './.next/session' // register session folder in .next folder
    };

    const sessionConfig: SessionOptions = {
        //secret: uid.sync(18),
        genid: (req) => {
            return 'app_' + uid.sync(18) // use UUIDs for session IDs
        },
        secret: 'SECRET',
        cookie: {
            maxAge: 43200 * 1000 // 12h
        },
        resave: false,
        saveUninitialized: true,
        store: new FileStore(fileStoreOptions)
    };

    app.use(bodyParser.json());
    app.use(session(sessionConfig));

    passport.serializeUser((user: any, done: (a: any, b: string) => void) => done(null, user));
    passport.deserializeUser((user: string, done: (a: any, b: any) => void) => done(null, user));

    app.use(passport.initialize());
    app.use(passport.session());

    // Add socketio to request to have available in express routes
    app.use(socketMiddleware(socketServer));

    app.use('/api/auth', routes.security); // anonymous
    app.use('/api/users', routes.users); // authenticated
    app.use('/api/patients', routes.patients); // authenticated
    app.use('/api/appointments', routes.appointments); // authenticated
    app.use('/api/consultations', routes.consultations); // authenticated
    app.use('/api/tasks', routes.tasks); // authenticated
    app.use('/api/documents', routes.documents); // authenticated
    app.use('/', routes.nextjs); // anonymous and authenticated

    // Handle all nextjs route
    app.all('*', (req: any, res: any) => nextHandler(req, res));

    server.listen(port, () => {
        console.log(`> Ready on http://localhost:${port}`);
    });
});

然后是我的socketserver.ts

import {Server, Socket} from "socket.io";
import * as http from 'http';
import {ServerEvents, ClientEvents} from "./SocketEvents";

class SocketServer {
    private io: Server;

    public constructor(server: http.Server) {
        this.io = new Server(server);
        this.initServer();
    }

    private initServer = (): void => {
        this.io.on(ServerEvents.CONNECTION, (socket: Socket) => {
            this.initClient(socket);
        });
    }

    private initClient = (socket: Socket): void => {
        console.log('New client connected with id', socket.id);
        // Emit status message for new connected client
        socket.emit(ServerEvents.STATUS, 'Connected on Gynemanager SocketIO server');

        socket.on(ClientEvents.USER_CONNECTED, async (socketId, username) => {
            const sockets = await this.io.fetchSockets(); // Get all connected clients

            // Add username to socket data
            sockets.forEach(socket => {
                if (socket.id === socketId) socket.data.username = username; // add username to new connected client
            })
        })

        socket.on(ServerEvents.DISCONNECT, (reason: string) => {
            console.log('Client disconnected', reason);
        })
    }
}

export default SocketServer

,然后socketmiddleware.ts

import {Response, NextFunction} from 'express';
import SocketServer from "./SocketServer";
import {CustomRequest} from "../types/express";

const socketMiddleware = (socketServer: SocketServer) => {
    return (req: CustomRequest, res: Response, next: NextFunction) => {
        req.socketServer = socketServer;
        next();
    }
}

export default socketMiddleware;

都会得到任何帮助。

I'm facing to an issue with a Socket.io server running throw an Express.js server with Next.js.

The server send error without any client connected. But clients can connect from browser without any issue...

Here is the error on console where the server is running :

Socket error TransportError: xhr poll error
    at Polling.onError (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transport.js:46:37)
    at Request.<anonymous> (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:255:18)
    at Request.Emitter.emit (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/@socket.io/component-emitter/index.js:143:20)
    at Request.onError (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:356:14)
    at Timeout._onTimeout (/Users/cedricbapst/Projects/gynemanager-frontend-next/node_modules/engine.io-client/build/cjs/transports/polling.js:329:30)
    at listOnTimeout (node:internal/timers:559:17)
    at processTimers (node:internal/timers:502:7) {
  description: 0,
  context: XMLHttpRequest {
    UNSENT: 0,
    OPENED: 1,
    HEADERS_RECEIVED: 2,
    LOADING: 3,
    DONE: 4,
    readyState: 4,
    onreadystatechange: [Function (anonymous)],
    responseText: 'Error: getaddrinfo ENOTFOUND undefined\n' +
      '    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26)',
    responseXML: '',
    status: 0,
    statusText: Error: getaddrinfo ENOTFOUND undefined
        at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:71:26) {
      errno: -3008,
      code: 'ENOTFOUND',
      syscall: 'getaddrinfo',
      hostname: 'undefined'
    },
    open: [Function (anonymous)],
    setDisableHeaderCheck: [Function (anonymous)],
    setRequestHeader: [Function (anonymous)],
    getResponseHeader: [Function (anonymous)],
    getAllResponseHeaders: [Function (anonymous)],
    getRequestHeader: [Function (anonymous)],
    send: [Function (anonymous)],
    handleError: [Function (anonymous)],
    abort: [Function (anonymous)],
    addEventListener: [Function (anonymous)],
    removeEventListener: [Function (anonymous)],
    dispatchEvent: [Function (anonymous)]
  },
  type: 'TransportError'
}
  socket.io-client:manager reconnect attempt error +1ms
  socket.io-client:manager will wait 5000ms before reconnect attempt +0ms

Just to be clear, this error is not on client side but on the server, clients from browser have a working connection even with this error from the server. The client does not get any error and works fine.

Here is my express.js server code :

import express, {Express} from 'express';
import * as http from 'http';
import next, {NextApiHandler} from 'next';
import passport from 'passport';
import session, {SessionOptions} from 'express-session';
import {Options} from "session-file-store";
const FileStore = require('session-file-store')(session);
import uid from 'uid-safe';
import bodyParser from 'body-parser';
import routes from './routes';
import SocketServer from "../socketio/SocketServer";
import socketMiddleware from "../socketio/SocketMiddleware";

const port: number = parseInt(process.env.PORT || '3000', 10);
const dev: boolean = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler: NextApiHandler = nextApp.getRequestHandler();

nextApp.prepare().then(() => {
    const app: Express = express();
    const server: http.Server = http.createServer(app);

    // Socket io server
    const socketServer = new SocketServer(server);

    // Session
    const fileStoreOptions: Options = {
        path: './.next/session' // register session folder in .next folder
    };

    const sessionConfig: SessionOptions = {
        //secret: uid.sync(18),
        genid: (req) => {
            return 'app_' + uid.sync(18) // use UUIDs for session IDs
        },
        secret: 'SECRET',
        cookie: {
            maxAge: 43200 * 1000 // 12h
        },
        resave: false,
        saveUninitialized: true,
        store: new FileStore(fileStoreOptions)
    };

    app.use(bodyParser.json());
    app.use(session(sessionConfig));

    passport.serializeUser((user: any, done: (a: any, b: string) => void) => done(null, user));
    passport.deserializeUser((user: string, done: (a: any, b: any) => void) => done(null, user));

    app.use(passport.initialize());
    app.use(passport.session());

    // Add socketio to request to have available in express routes
    app.use(socketMiddleware(socketServer));

    app.use('/api/auth', routes.security); // anonymous
    app.use('/api/users', routes.users); // authenticated
    app.use('/api/patients', routes.patients); // authenticated
    app.use('/api/appointments', routes.appointments); // authenticated
    app.use('/api/consultations', routes.consultations); // authenticated
    app.use('/api/tasks', routes.tasks); // authenticated
    app.use('/api/documents', routes.documents); // authenticated
    app.use('/', routes.nextjs); // anonymous and authenticated

    // Handle all nextjs route
    app.all('*', (req: any, res: any) => nextHandler(req, res));

    server.listen(port, () => {
        console.log(`> Ready on http://localhost:${port}`);
    });
});

And then my SocketServer.ts

import {Server, Socket} from "socket.io";
import * as http from 'http';
import {ServerEvents, ClientEvents} from "./SocketEvents";

class SocketServer {
    private io: Server;

    public constructor(server: http.Server) {
        this.io = new Server(server);
        this.initServer();
    }

    private initServer = (): void => {
        this.io.on(ServerEvents.CONNECTION, (socket: Socket) => {
            this.initClient(socket);
        });
    }

    private initClient = (socket: Socket): void => {
        console.log('New client connected with id', socket.id);
        // Emit status message for new connected client
        socket.emit(ServerEvents.STATUS, 'Connected on Gynemanager SocketIO server');

        socket.on(ClientEvents.USER_CONNECTED, async (socketId, username) => {
            const sockets = await this.io.fetchSockets(); // Get all connected clients

            // Add username to socket data
            sockets.forEach(socket => {
                if (socket.id === socketId) socket.data.username = username; // add username to new connected client
            })
        })

        socket.on(ServerEvents.DISCONNECT, (reason: string) => {
            console.log('Client disconnected', reason);
        })
    }
}

export default SocketServer

And then the SocketMiddleware.ts

import {Response, NextFunction} from 'express';
import SocketServer from "./SocketServer";
import {CustomRequest} from "../types/express";

const socketMiddleware = (socketServer: SocketServer) => {
    return (req: CustomRequest, res: Response, next: NextFunction) => {
        req.socketServer = socketServer;
        next();
    }
}

export default socketMiddleware;

Any help will be appreciate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄与心 2025-02-01 20:13:15

最后,我弄清楚我的问题是什么。

我从_app.tsx初始化了socket.io连接,因为这是我使用React上下文提供商将我的socketClient.ts绑定到整个应用程序的地方。

要解决该问题,我必须将连接初始化从_app.tsx移动到另一页(对于从登录页面重定向的页面中的我的情况),并检查是否已经在其他页面上启动了连接,以避免套件以避免使用多人连接,然后一切都按预期工作。

Finally I figure out what was my problem.

I initialised the socket.io connection from _app.tsx for clients because this is the place where I use React context provider to bind my SocketClient.ts to the whole application.

To fix the issue I have to move the connection initialisation from _app.tsx to another page (for my case from the page redirected from login page), and check if connection is already init on the other page where socket is also needed to avoid multi connection and then everything works as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文