代码之家  ›  专栏  ›  技术社区  ›  Amarsh

Express无法在邮件发送后设置邮件头

  •  0
  • Amarsh  · 技术社区  · 6 年前

    我有一种情况,我正在从node/express运行一个交互式C控制台程序。程序以无限循环运行,从命令行接受一个字符串,并将其回传。

    以下代码在我第一次调用时有效 http://localhost:3000?command=hello

    下次,节点因报告而崩溃 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!'))
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   jfriend00    6 年前

    当您试图对一个传入请求发送多个响应时,就会出现这个特定的错误。当我检查您的代码时,我看到这段代码:

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

    可以接收 data 事件不止一次,当它发生时,它将调用 done(stdout) 多次,这将导致呼叫方呼叫 res.send() 不止一次。

    有了溪流,你不知道有多少次 数据 将调用事件。它只能被调用一次,或者可以用许多小数据块多次调用。


    另外,你只有一个 script 你所有的请求都使用。所以,每次你打电话 sendToShell() ,你又加了一个 script.stdout.on('data', ...) 事件处理程序,这样它们将堆积起来,您将有重复项,导致您调用 done() 一次以上 数据 事件。如果您要坚持这个结构,那么您需要一种方法来知道最后一个命令的所有数据何时发送,然后您需要删除该事件处理程序,这样它们就不会堆积起来。


    仅供参考,此代码还存在并发性问题,因为多个请求可能进入您的服务器,导致您运行一个命令,而您不知道哪个响应属于哪个命令。如果只打开一个shell,则可能需要将命令排队到shell,这样在上一个命令完成之前,就不会发送下一个命令或设置其事件处理程序来读取响应。这样就不会从错误的命令中读取响应。