【问题标题】:node js post request only works second time节点js发布请求仅第二次有效
【发布时间】:2017-04-18 06:35:30
【问题描述】:

我有一个奇怪的问题,当我提交表单时,它会重定向到表单操作 URL,然后显示空白页面。当我再次重新加载它时,它会显示数据。

index.jade - http://172.18.0.60:3000/

  form#command(action='runcommand', method='post')
    input#cmdls(type='checkbox', name='cmdls', value='ls -la')
    label(for='cmdls') List Files
    br
    input#cmdpwd(type='checkbox', name='cmdpwd', value='pwd')
    label(for='cmdpwd') Print Working Directory
    br
    input#cmddate(type='checkbox', name='cmddate', value='date')
    label(for='cmddate') Date
    br
    input.button(type='submit', value='Run')

app.js

var tmp=""; 
app.post('/runcommand',function(req,res){

    for (var key in req.body) {

            console.log(key);
            function puts(error, stdout, stderr) { sys.puts(stdout) }
            exec(req.body[key], function(error, stdout, stderr) {
              if (!error) {
                    tmp+=stdout;                       
              } else {
                tmp+=stderr;
              }
            });

    }

    res.render("result",{ data: tmp });

});

result.jade - http://172.18.0.60:3000/runcommand

扩展布局

block content
    h1= "Result"   
    pre=  data

当我提交表单时,它会重定向到http://172.18.0.60:3000/runcommand,只显示 h1,当我再次重新加载它时,它会显示 data

为什么会这样?

【问题讨论】:

    标签: javascript node.js express command-line-interface


    【解决方案1】:

    exec() 是异步的,所以它在你调用res.render() 之后完成。因此,您只需要在所有 exec() 调用完成后进行渲染。如果您使用 Promise 和 Promise.all() 来跟踪所有 exec() 调用的完成时间,这可能会更容易编码,但您也可以使用计数器来了解最后一个调用的完成时间。

    这是一个使用计数器的方案:

    app.post('/runcommand', function(req, res) {
    
        let keys = Object.keys(req.body);
        let cnt = 0;
        let tmp = '';
        if (!keys.length) {
            // render something when there were no keys
            res.render(...)
        } else {
            keys.forEach(function(key) {
                console.log(key);
    
                exec(req.body[key], function(error, stdout, stderr) {
                    if (!error) {
                        tmp += stdout;
                    } else {
                        tmp += stderr;
                    }
                    ++cnt;
                    // if all exec calls have finished, the render
                    if (cnt === keys.length) {
                        res.render("result", {data:tmp});
                    }
                });
            });
        }
    });
    

    附:这段代码看起来允许任何客户端在服务器上运行任何任意程序(如果它在路径中或者他们可以构建完整路径)。这看起来很危险。

    附言在处理程序之外累积tmp,就像您在原始代码中所做的那样,对于使用您的服务器的多个用户来说是一场灾难,因为多个请求可能会影响tmp 中的任何一个值。像这样的累积数据需要在请求处理程序内的局部变量中或在请求对象的属性中,这样它就不会与正在处理的其他请求发生冲突。

    【讨论】:

    • 太棒了!解释。
    猜你喜欢
    • 2017-12-24
    • 2011-12-09
    • 1970-01-01
    • 2015-11-06
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多