【发布时间】:2020-10-22 00:42:54
【问题描述】:
我在执行 express (v4) 路由时遇到双重发射问题。
例如,让我们运行下面的代码。请求(管道)和 mkdir 将立即启动(竞争条件)并且会有错误,关于该文件夹不存在(mkdir 无法足够快地创建它,在请求启动并开始管道数据之前)。此错误的原因是用户被重定向到需要重新填写表单的页面 X。现在(重定向并重新填充表单后)一切正常(因为文件夹在数据到达时确实存在,因为它是之前创建的 - 导致异步操作必须完成? - 即使用户已经在“后面”执行代码重定向)但是发出两次 - 一次用于旧数据,一次用于新数据(复制 HTML 页面结构的一部分)。
x.js 文件中的路由:
router.post('/Y', function(req, res) {
request(opt, function(err, resp, body) {
if (resp.statusCode === 200) {
res.render('Y'); // so the emits can target something (they build html structure on page 'Y' with proper data)
function socCon()
{
var room = '';
return new Promise(function(resolve, reject)
{
req.io.on('connection', function(socket)
{
room = 'room-' + socket.id;
socket.join(room);
if (socket.join(room)) {
resolve(room);
}
else {
reject(console.log('error'));
}
});
});
}
socCon().then(data).catch(function(error)
{
console.log(error);
});
function data(room) {
var myFolder = 'myFolder/';
fs.mkdir(myFolder, {recursive : true}, function(err) {
if (err) {console.log(err);}
});
var file = fs.createWriteStream(myFolder + 'data.html', 'utf8');
sio.emit('msg', {emit : emit}); // socket.io emits - with use of express route POST on page 'X'
});
}
else {
res.render('X', {ERRORS : ERRORS});
res.end();
}
}).on('response', function(response) {
}).pipe(file).on('error', function(err) {
res.render('X', {ERRORS : ERRORS}); // we inform the user that he put wrong data in input field or that there is internal server error (whatever)
res.end();
// so we end 'Y' page connection here (but socket.io somehow collect all the data, emit it later on - when same route is hit again) and socket.sendBuffer does not work)
});
)};
有没有办法阻止旧的排放?我试过socket.sendBuffer = [];(@jfreind00 建议在 -socket.io stop re-emitting event after x seconds/first failed attempt to get a response)无济于事。理想的情况是......当有重定向时停止整个请求。但是你不能阻止异步代码的执行(或者我只是不知道怎么做)。
客户页面 Y:
<!DOCTYPE html>
<html>
<head>
<title>TITLE</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
socket.on('connect', function() {
socket.sendBuffer = []; // does not work...
});
socket.on('msg', function(msg) {
// some HTML mutation here
});
</script>
</body>
</html>
当然代码要复杂得多,但这足以(我认为)显示问题。这个“应用程序”可能是一个糟糕的设计,但我不知道如何修复它。
index.js 文件(主“app”文件):
var x = require('./routes/x.js');
var app = express();
app.use('/', x);
app.use(function(req, res, next) {
req.io = io;
next();
});
var io = require('socket.io')(server);
io.on('connection', function (soc) {
soc.on('disconnect', function(reason) {
console.log(reason);
});
// etc.
});
【问题讨论】:
-
我实际上不明白您在这里问的是哪个特定问题。请概述发生的确切步骤以及您想要发生的事情。它是否从浏览器开始转到
http://somedomain.com/Y,那么究竟会发生什么?目前尚不清楚您要向谁发送.emit(),因为您无法.emit()访问正在被浏览器加载的页面。 -
另外,
request()和 `.pipe() 背后的原因是什么?你想用你创建的文件做什么? -
somedomain.com/X 是带有输入字段的起始域。如果用户填写它,路线会将他带到somedomain.com/Y。在 Y 处,当他浏览页面时,请求的结果(在路由 POST Y 中)被发送并更新页面。但有时(例如,当文件夹未按时创建时 - 用户被重定向到需要再次填写输入的页面 X)发出两次发送。请求检查并下载数据,我想存储文件(带有请求的数据),以便稍后与新文件进行比较。
-
那么,为什么不从解决您显然已经知道的
mkdir()问题开始呢?谁得到双重发射?我还不明白那部分。 -
是的,它很容易通过 asyncs/await 修复,我只是想说明问题 - 但仍然不应将排放量加倍。用户获得双重发射(旧数据,可能导致异步代码在“后面”运行+他刚才传递的新数据)。当服务器例如给我们错误时也会发生这种情况 - 当再次检查相同的数据时,用户确实会得到两倍/三倍等。 Socket.io 不知何故知道此 id 已连接到此用户(代理?),即使每个新的套接字 io 连接都使用新 ID,它也会设法将旧用户 ID 与新用户 ID(?)连接并发出数据。跨度>
标签: javascript node.js socket.io