我遇到从节点/表达式运行交互式C#控制台程序的情况。该程序在无限循环中运行,从命令行接受一个字符串,然后将其回显。
以下代码在我第一次致电http://localhost:3000?command=hello
时有效
下次,Node通过报告Can't set headers after they are sent.
如果将const script = spawn('/Users/amarshanand/shadowClient/myscript.sh');
移到sendToShell()
上是可行的,但是由于我必须启动新的shell和脚本,所以需要花费更长的时间。
如何使它像启动一次并为每个请求接受命令一样工作。
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!'))
答案 0 :(得分:2)
当您尝试向传入请求发送多个响应时,会发生该特定错误。在检查您的代码时,我看到了这段特定的代码:
script.stdout.on('data', (stdout) => {
console.log(`stdout: ${stdout}`);
done(stdout);
});
可以多次接收data
事件,当它收到时,它将多次调用done(stdout)
,这将导致调用者多次调用res.send()
。
对于流,您不知道data
事件将被调用多少次。可以只调用一次,也可以用大量小数据多次调用它。
此外,您只有一个script
供您所有请求使用。因此,每次调用sendToShell()
时,都会添加另一个script.stdout.on('data', ...)
事件处理程序,这样它们将堆积起来,并且会有重复项,导致您为每个{{1 }}事件。如果要坚持这种结构,那么您需要一种方法来知道何时为最后一条命令发送了所有数据,然后需要删除该事件处理程序,以免它们堆积。
仅供参考,此代码还存在并发问题,因为可能有多个请求进入服务器,导致您运行命令,并且您不知道哪个响应属于哪个命令。如果只打开一个外壳,则可能需要将命令排队到外壳上,以便在上一个命令完成之前不发送下一个命令或设置其事件处理程序以读取响应。这样,您就不会从错误的命令中读取响应。