Как сделать HTTP-запрос с использованием Node.js при вводе пользователем? - PullRequest
0 голосов
/ 12 октября 2018

Итак, я запустил этот простой проект в node.js, где клиент отправляет запрос POST, содержащий в своем теле команду CMD Windows.

Сервер получает запрос 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.

В настоящее время я думаю, что это происходит потому, что функция requestCommand завершается до обработки ошибки (до того, как событие error сгенерировано, и функция обратного вызова, котораявозвращает ошибку (вызывается), поскольку функция обратного вызова для http.request явно асинхронна и перед серверомотвечает или выдается ошибка, функция завершается и, следовательно, ничего не возвращает (undefined)

Поэтому мой вопрос: могу ли я сохранить эту функцию работающей, пока не будет выполнена асинхронная команда?

Илиесли это невозможно, есть ли другой подход к этому?Как бы вы отправляли запросы на этот сервер после определенного события, инициированного пользователем, такого как ввод данных?

РЕДАКТИРОВАТЬ: Я действительно не заинтересован в использовании сторонних модулей, как я ужеМожно.Этот проект действительно бессмысленен и только для меня, чтобы учиться, поэтому я использую только основные модули для этого.В частности, я использую только HTTP для выполнения запросов (не sync-request и т. Д.)

1 Ответ

0 голосов
/ 12 октября 2018

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();
}
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...