Переслать запрос клиенту и ждать ответа Экспресс - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь создать конечную точку, которая будет получать запрос, отправлять данные запроса клиенту WebSocket, ждать события, а затем отправлять ответ обратно с помощью команды express + socketio. Этот вопрос похож на него: Ожидание события socketio внутри экспресс-маршрута

1) Получить запрос на http://localhost:3000/endpoint

2) Записать событие в веб-сокеты как 'req'

3) Дождаться события 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 голосов
/ 29 апреля 2018

Обратите внимание, что:

socket.on('res', function (data) {
    res.status(200).json(data);
});

Вызывается каждый раз, когда сокет отправляет ответ, таким образом, показывая вышеупомянутую ошибку. Вы должны отсоединить слушателя внутри функции обратного вызова.

0 голосов
/ 29 апреля 2018

Сохраните массив экспресс-ответов и установите идентификатор для каждого запроса. Так что его можно использовать позже и удалить при необходимости.

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);
0 голосов
/ 29 апреля 2018

Вы пытаетесь выполнить две разные асинхронные задачи для одних и тех же данных.

Сначала возьмите socket.on('res'...) из app.get().

Отправьте обратно res.status(200) немедленно с экспрессом, чтобы сообщить, что вы получили запрос и он обрабатывается. Затем отправьте сообщение сокета клиенту, используя socket.io, когда оно будет завершено. Вы хотите сохранить идентификатор клиента сокета подключенных пользователей и использовать 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();

Сервер

перевезти вещи и обращаться с ними без использования экспресса вообще

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...