Express Не удается установить заголовки после их отправки - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть ситуация, когда я запускаю интерактивную консольную программу C # из узла / экспресса. Программа работает в бесконечном цикле, принимает строку из командной строки и возвращает ее обратно.

Следующий код работает впервые, когда я звоню http://localhost:3000?command=hello

В следующий раз Node завершает работу, сообщая Can't set headers after they are sent.

Если переместить const script = spawn('/Users/amarshanand/shadowClient/myscript.sh'); в sendToShell(), это работает, но, поскольку мне нужно запустить новую оболочку и скрипт, это займет гораздо больше времени.

Как мне сделать так, чтобы он запускался один раз и принимал команду для каждого запроса.

const express = require('express')
const app = express()

const { spawn } = require('child_process');
const script = spawn('/Users/amarshanand/shadowClient/myscript.sh');

const sendToShell = (command, done) => {

    script.stdout.on('data', (stdout) => {
        console.log(`stdout: ${stdout}`);
        done(stdout);
    });

    script.stderr.on('data', (stderr) => {
        console.log(`error: ${stderr}`);
    });

    script.stdin.write(`${command}\n`);

}

app.get('/', (req, res) => {
    sendToShell(req.query.command, result => res.send(`${result}`));
})

app.get('/getstate', (req, res) => {
    res.send('state');
})

app.post('/setstate:state', (req, res) => res.send('posted state'));

app.listen(3000, () => console.log('Example app listening on port 3000!'))

1 Ответ

0 голосов
/ 04 сентября 2018

Эта конкретная ошибка возникает при попытке отправить более одного ответа на входящий запрос. Когда я проверяю ваш код, я вижу, что этот конкретный фрагмент кода:

script.stdout.on('data', (stdout) => {
    console.log(`stdout: ${stdout}`);
    done(stdout);
});

Может получить событие data более одного раза, и когда это произойдет, оно будет вызывать done(stdout) более одного раза, что вызовет вызывающего абонента res.send() более одного раза.

С потоками вы не представляете, сколько раз будет вызвано событие data. Его можно вызывать только один раз или много раз с большим количеством небольших фрагментов данных.


Кроме того, у вас есть только один script, который используется во всех ваших запросах. Таким образом, каждый раз, когда вы вызываете sendToShell(), вы добавляете еще один обработчик события script.stdout.on('data', ...), чтобы они накапливались, и у вас будут дубликаты, заставляющие вас вызывать done() более одного раза для каждого события data. Если вы собираетесь придерживаться этой структуры, вам нужен способ узнать, когда все данные были отправлены для последней команды, а затем вам нужно удалить этот обработчик событий, чтобы они не накапливались.


К вашему сведению, в этом коде также есть проблемы с параллелизмом, поскольку на ваш сервер может поступать несколько запросов, в результате которых вы запускаете команду, и вы не будете знать, какой ответ принадлежит какой команде. Если вы собираетесь оставить только одну открытую оболочку, то вам, вероятно, нужно поставить команды в очередь, чтобы вы не отправляли следующую команду и не настраивали ее обработчики событий для чтения ответа до тех пор, пока не будет выполнена предыдущая команда. Таким образом, вы не будете читать ответ от неправильной команды.

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