向ws客户端转发请求并等待响应Express

时间:2018-04-29 14:00:23

标签: node.js express socket.io

我正在尝试构建一个接收请求的端点,将请求数据发送到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]:发送后无法设置标头   给客户

3 个答案:

答案 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);