我正在创建一个node.js应用程序,它有一个react客户端和一个express/socketio后端以及passport身份验证。我试图从客户端发出一个socketio事件,然后让后端响应,但似乎在发出请求到后端处理请求之间的某个时间丢失了请求。
下面是我认为与当前问题相关的所有文件。后端位于localhost:5000上,客户端位于localhost:3000上。正如我所说,在Organization.js中标记的那一行之前,一切都很顺利。但在该行处或该行之后,事件可能会被发送,但socket.js中的相应路由都没有命中。
后端启动文件- app.js
'use strict';
import express from 'express'
import { createServer } from 'http'
import path from 'path'
import { fileURLToPath } from 'url';
import logger from 'morgan'
import cookieParser from 'cookie-parser'
import index from './routes/index.js'
import session from 'express-session'
import passport from './src/auth.js'
import { Server } from 'socket.io'
import { CrashCollector } from 'crashcollector'
new CrashCollector('crash_logs', (err, exit) => {
console.log('Cleaning up...')
console.log('Saving some stuff...')
// Calls callback funtion executing process.exit()
// You can also just write process.exit() here
exit()
})
const app = express();
const server = createServer(app)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const io = new Server(server, {
cookie: { maxAge: 24 * 60 * 60 * 1000 },
cors: {
origin: 'http://localhost:3000',
credentials: true
}
})
const sessionMiddleware = session({
secret: "changeit", resave: false,
saveUninitialized: false
});
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(sessionMiddleware)
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', index);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
console.log('dev error handler')
res.status(err.status || 500);
res.end()
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
console.log('prod error handler')
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000); //process.env.PORT = 5000
server.listen(app.get('port'), _ => {
console.log(`Server listening on port ${app.get('port')}`)
})
export {
io,
sessionMiddleware
}
后端- socket.js
import { io, sessionMiddleware } from '../app.js'
import passport from '../src/auth.js'
import { getSequel } from '../src/database.js'
const wrap = middleware => (socket, next) =>
middleware(socket.request, {}, next);
io.use((_, next) => {
console.log('connection attempt')
next()
})
io.use(wrap(sessionMiddleware));
io.use(wrap(passport.initialize()));
io.use(wrap(passport.session()));
io.use((con, next) => {
console.log('socket check', !!con.request.user)
if (con.request.user) {
next()
} else {
next(new Error('unauthorized'))
}
});
io.on('connection', (con) => {
console.log(`new connection ${con.id}`);
con.on('confirm', cb => {
cb(con.request.user.name);
});
con.on('eventTable', _ => {
console.log('eventTable')
con.emit(con.request?.user?.getEvents()?.map(e => e.toJSON()))
})
});
客户端启动文件- index.js
import React from 'react'
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App/App';
import { io } from 'socket.io-client'
import configs from '../package.json'
const container = document.getElementById('root');
const root = createRoot(container);
export const socket = io.connect(configs.proxy, { //configs.proxy = http://localhost:5000
withCredentials: true
})
socket.on('connect', _ => {
console.log('socket connect', socket.id)
})
socket.on('connect_error', _ => {
console.log('socket connect_error')
})
socket.on('disconnect', _ => {
console.log('socket disconnect')
})
socket.prependAny((eventName, ...args) => {
console.log(eventName, args)
})
root.render((
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
));
客户端- App.js
import React from 'react'
import { Route, Routes } from 'react-router-dom'
import './App.css'
import Login from './pages/Login'
import Home from './pages/Home'
import LoginCheck from './helper/LoginCheck'
const App = () => {
console.log('app')
return (
<Routes>
<Route exact path="/" element={<LoginCheck />} >
<Route index element={<Home />} />
</Route>
<Route path="/login" element={<Login />} />
</Routes>
)
}
export default App;
客户端- Home.js
import React, { useState } from 'react';
import Org from './Organization'
const Home = () => {
console.log('home')
return localStorage.getItem('isOrg') ? (
<Org />
) : (
'Employee'
)
}
export default Home;
客户端-组织. js
import React, { createElement, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'
import Countdown from 'ds-countdown'
import { socket } from '../../index'
const Org = () => {
console.log('org')
const setTable = (raffles) => {
console.log('cb eventTable')
JSON.parse(raffles).forEach(raffle => {
const row = createElement('tr')
const name = createElement('td')
name.append(raffle.name)
const num = createElement('td')
num.append(raffle.num)
const started = Date.parse(raffle.start) >= Date.now()
const countdown =
<><td>
<p style={{ color: started ? 'red' : 'green' }}>
{started ? 'Starts' : 'Ends'} in:
<div id={`timer${raffle.id}`} />
</p>
</td></>
const action = createElement('td')
const edit = createElement('button')
edit.addEventListener('click', e => {
//goto edit at raffle.id
alert('edit')
})
const end = createElement('button')
end.addEventListener('click', e => {
//set timer to 0
alert('start/end')
})
action.append(edit)
action.append(end)
row.append(name)
row.append(num)
row.append(countdown)
row.append(action)
document.getElementById('eventTable').append(row)
new Countdown({
id: `timer${raffle.id}`,
targetTime: started ?
raffle.end : raffle.start
})
})
}
useEffect(() => {
console.log('useEffect')
**socket.emit('eventTable')** //THIS IS WHERE IT BREAKS
socket.on('eventTable', setTable)
return () => {
socket.off('eventTable', setTable)
}
})
return (<>
<h1 style={{ textAlign: 'center' }}>
{localStorage.getItem('name')}
</h1>
<table style={{ marginLeft: 'auto', marginRight: 'auto' }}
border="1"><caption>
<h3>Scheduled Raffles</h3>
</caption>
<tbody id="eventTable">
<tr>
<th>Name</th>
<th>Num Participants</th>
<th>Countdown</th>
<th>Action</th>
</tr>
<tr>
<td>Test</td>
<td>10</td>
<td>10:10:04</td>
<td><button> Edit </button> <button> End Now </button> <button> Stop </button></td>
</tr>
</tbody>
</table>
</>);
}
export default Org;
我在前端没有收到任何错误。实际上,客户端说连接已经建立,这要归功于index.js中的socket.on('connect')。socket.js文件中没有任何console.logs被激活,所以我有理由相信路由没有被命中。我还激活了socket上的Debugging,但那里的日志对我没有太大帮助:
Server listening on port 5000
socket.io:server incoming connection with id 1wpATq-xiQ1jHttwAAAA +2s
socket.io-parser decoded 0 as {"type":0,"nsp":"/"} +0ms
socket.io:client connecting to namespace / +0ms
socket.io:namespace adding socket to nsp / +0ms
socket.io:socket socket connected - writing packet +0ms
socket.io:socket join room f6lna-kbntjuwffpAAAB +3ms
socket.io-parser encoding packet {"type":0,"data":{"sid":"f6lna-kbntjuwffpAAAB"},"nsp":"/"} +7ms
socket.io-parser encoded {"type":0,"data":{"sid":"f6lna-kbntjuwffpAAAB"},"nsp":"/"} as 0{"sid":"f6lna-kbntjuwffpAAAB"} +1ms
POST /login 200 653.887 ms - 37
socket.io-parser decoded 2["eventTable"] as {"type":2,"nsp":"/","data":["eventTable"]} +3s
socket.io:socket got packet {"type":2,"nsp":"/","data":["eventTable"]} +3s
socket.io:socket emitting event ["eventTable"] +0ms
socket.io:socket dispatching an event ["eventTable"] +1ms
socket.io-parser decoded 2["eventTable"] as {"type":2,"nsp":"/","data":["eventTable"]} +15ms
socket.io:socket got packet {"type":2,"nsp":"/","data":["eventTable"]} +2ms
socket.io:socket emitting event ["eventTable"] +0ms
socket.io:socket dispatching an event ["eventTable"] +1ms
2条答案
按热度按时间uxh89sit1#
服务器端
socket.emit
调用应将事件名称作为第一个参数。bvuwiixz2#
问题是我在初始化sockets.js路由之前启动了服务器。我不得不在后端做一些重新配置,但基本上我修复它的方法是在sockets.js中创建一个快速路由器,将所述路由器导入app.js,然后在调用
server.listen(PORT)
之前执行app.use('/socket', sockets)
。下面是我的后端的最终状态:新后端文件-init.js:
app.js:
sockets.js: