用户输入后如何使用Node.js发出HTTP请求?

时间:2018-10-12 19:44:06

标签: javascript node.js asynchronous synchronization

因此,我在node.js中启动了这个简单的项目,客户端在其中发送了一个POST请求,该请求的主体中包含Windows CMD命令。

服务器接收到POST请求,提取CMD命令,然后在运行该命令后,以该命令的输出作为响应。

当我发出一个请求时,此方法很好用,但是随后我设置了一个系统,反复询问用户该命令,然后以输入的命令作为正文发送POST请求。

这是客户端代码:(不包含服务器端,因为它无关紧要)

var http = require("http");
var readline = require("readline");
var rl = readline.createInterface(process.stdin, process.stdout);

var options = {
    hostname: "localhost",
    port: 3001,
    path: "/",
    method: "POST",
    headers: {
        "Content-Type": "text/plain",    // all command must be string
        "Content-Length": 0   // changes based on what the command is
    }
};

function requestCommand(hostname, port, command) {

    // Some of the options of the request need to be changed based on
    // what the command is
    options.hostname = hostname;
    options.port = port;
    options.headers["Content-Length"] = command.length;

    var req = http.request(options, function(res) {
        console.log(`Got response. Status code: ${res.statusCode}`);

        var resData = "";
        res.setEncoding("utf-8");

        res.on("data", function(chunk){
            resData += chunk
        });

        res.on("end", function(){
            return resData;
        })

    })

    req.on("error", function (e){
        return "\n\n\n ---------------\nERROR OCCURED IN THE REQUEST.\nREQUEST NOT SENT\n--------------" + e.stack;

    })

    req.write(command);
    req.end();
}

rl.setPrompt("What command would you like to request from the server?: ");
rl.prompt();

rl.on("line", function(data){
    if (data === "exit") {
        console.log("\n\n\Exiting appplication...\n\n");
        process.exit();
    } else {
        console.log("processing..");
        var out = requestCommand("localhost", 3001, data);
        console.log(`\n\n${out}\n\n`);
        rl.prompt();
    }
});

如果我在不首先创建服务器的情况下运行它,则没有得到错误消息,而是得到undefined

当前,我认为这是因为requesthttp函数在处理错误之前结束(在发出error事件之前,并且调用了返回错误的回调函数),因为http.request的回调函数显然是异步的,并且在服务器响应或发出错误之前,该函数结束并因此不返回任何内容(undefined

所以我的问题是:在异步命令完成之前,我可以一直运行该功能吗?

或者这是不可能的,是否有其他方法?在用户触发某些事件(例如数据输入)时,您将如何向该服务器发送请求?

编辑:我已经对使用第三方模块确实不感兴趣。这个项目真的没有意义,仅在这里供我学习,因此我仅使用核心模块。更具体地说,我仅使用HTTP发出请求(而不是同步请求,例如e.t.c。)

1 个答案:

答案 0 :(得分:1)

requestCommand必须返回一个用resData解析并因错误而被拒绝的承诺:

 function requestCommand(hostname, port, command) {

  return new Promise((resolve, reject) => { // immeadiately return a Promise that can be resolved/rejected later
    // Some of the options of the request need to be changed based on
    // what the command is
    options.hostname = hostname;
    options.port = port;
    options.headers["Content-Length"] = command.length;

    var req = http.request(options, function(res) {
      console.log(`Got response. Status code: ${res.statusCode}`);

      var resData = "";
      res.setEncoding("utf-8");

      res.on("data", function(chunk){
          resData += chunk
      });

      res.on("end", function(){
          resolve(resData); // resolve, return won't work here
      });
    });

    req.on("error", function (e){
      reject(e); // reject here, don't handle it
    });

    req.write(command);
    req.end();
   });
}

这样,您可以简单地使请求处理程序async,然后使await成为函数调用:

rl.on("line", async function(data){ // make the function async so that we can work with promises more easily
  if (data === "exit") {
    console.log("\n\n\Exiting appplication...\n\n");
    process.exit();
  } else {
    console.log("processing..");
    try {
      var out = await requestCommand("localhost", 3001, data); // "await" lets async code look like sync code, but it is still async
       console.log(`\n\n${out}\n\n`);
    } catch(e) { // the reject() call will end up here
      console.log("invalid command " + e.stack); // handle here
    }
    rl.prompt();
}
});