我正在尝试构建一个接收请求的端点,将请求数据发送到WebSocket客户端,等待事件,然后使用express + socketio发回响应。这个问题类似于:Wait for socketio event inside express route
1)在http://localhost:3000/endpoint
接收请求2)将事件发送到Web套接字作为' req'
3)等待' res' res来自ws的事件
4)发送收到的活动详情作为快递的回复。
以下是我实施的方式:
server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
var socket;
io.on('connection', function (s) {
socket = s;
});
http.listen(3000);
app.get('/endpoint', function (req, res) {
console.log('new request')
io.emit('req', { data: 'hello' });
socket.on('res', function (data) {
res.status(200).json(data);
});
});
的index.html
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('req', (data) => {
console.log(data)
socket.emit('res', data);
});
</script>
该脚本适用于/endpoint
上的第一个请求。但如果我再次点击网址,它会说
错误[ERR_HTTP_HEADERS_SENT]:发送后无法设置标头 给客户
答案 0 :(得分:1)
请注意:
socket.on('res', function (data) {
res.status(200).json(data);
});
每次套接字发送响应时都会被调用,从而显示上述错误。你应该在回调函数中取消绑定侦听器。
答案 1 :(得分:0)
您正在尝试为同一数据执行两个不同的异步任务。
首先,从socket.on('res'...)
中取出app.get()
。
立即发送回res.status(200)
,快递说你收到了请求并正在处理。然后在socket.io完成后使用socket.io将套接字消息发送到客户端。您需要保存已连接的用户套接字客户端ID,并使用io.to(socketId).emit(...data...)
执行此操作
另一个选项就是我一直在做的事情(假设它不是你发送的疯狂的大型数据有效负载) 只需在整个过程中使用socket.io。
<强>客户端强>
function makeRequest () {
socket.on('data-complete--error', function ( error ) {
// ... message to user :(
// also remove these handlers when finished
socket.off('data-complete--error');
socket.off('data-complete--success');
});
socket.on('data-complete--success', function ( data ) {
// ... message to user :)
// ... handle data
// also remove these handlers when finished
socket.off('data-complete--error');
socket.off('data-complete--success');
});
socket.emit('request-data');
}
makeRequest();
服务器强>
将你的东西移出并处理,而不使用快递
答案 2 :(得分:0)
保留一系列明确的回复并为每个请求设置一个id。所以它可以在以后使用并在需要时删除。
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var timeout = require('connect-timeout');
var uuid = require('uuidv4');
var _ = require('lodash');
app.use(timeout('10s'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
let responses = []
io.on('connection', (socket) => {
socket.on('res', (e) => {
var obj = _.find(responses, r => r.id === e.id);
obj.res.send(e)
_.remove(responses, r => r.id === e.id);
})
})
app.get('/endpoint', (req, res) => {
const id = uuid()
io.emit('req', { id, ip: req.ip, header: req.headers, method: req.method });
responses.push({ id, res })
});
http.listen(3000);