Событие сработало, но не весь код выполнен - PullRequest
0 голосов
/ 19 марта 2019

Я работаю над проектом на github с именем lan-info .
у меня есть следующий код

let arpSweepCommand = './arpSweep.sh';
app.get('/arp', (req, res) => {
  console.log('we have a working signal!');
  executeCommand(arpSweepCommand, req, res, false);
  fs.readFile('command_output/arpedHosts.txt', 'utf-8', (error, data) => {
    if (error) {
      res.send(error);
    } else {
      res.send(data);
    }
  })
})

и arpSweep.sh содержит:

timeout 10s netdiscover -P > command_output/arpedHosts.txt

и в моем интерфейсе у меня есть вызов Jquery AJAX:

arpButton.click(function () {
  loader.show();
  $.ajax({
    method: 'GET',
    url: '/arp',
    success: function (data) {
      console.log(data);
      commandOutput.append(data);
      loader.hide();
    }
  })
})

я знаю, что нет синтаксических ошибок, потому что webpack компилирует код интерфейса без жалоб; и я знаю, что бэкэнд перехватывает запрос, так как всякий раз, когда я нажимаю arpButton, он печатает «у нас есть сигнал!» на сервере.
но проблема в loader.show () / hide (), кажется, ничего не делает только в этом запросе ajax. Я знаю, что это специфично для этого запроса ajax, потому что у меня есть похожие запросы, которые прекрасно работают.
для меня проблема в том, что информация не добавляется автоматически к commandOutput.
мне нужно нажать arpButton в другой раз, чтобы вывод был добавлен к commandOutput.
но загрузчик не появится у меня, я знаю, что загрузчик не появляется и исчезает очень быстро, потому что вызов ajax занимает не менее 10 секунд.
другая проблема заключается в том, что данные не появляются автоматически через 10 секунд в commandOutput. Я проверил, что только загрузчик работает со сбоями, подождав 30 минут после нажатия arpButton, но ничего не происходит; когда я продолжаю нажимать arpButton снова, вывод отображается мгновенно.
так почему же страница не обновляется сама? вместо этого он заставляет меня нажать кнопку. если вам нужна дополнительная информация, вы можете нажать на ссылку проекта над файлами:
src / index.js
index.js
arpSweep.sh
ПРИМЕЧАНИЕ. Обязательно измените подсеть в верхней части index.js, если вы не используете подсеть, которую вы используете (автоматическое определение подсети - это функция, которую я планирую реализовать позже).
РЕДАКТИРОВАТЬ: после попытки прочитать файл в качестве обратного вызова для executeCommand:

function executeCommand (command, req, res, sendRes = true, callback) {
  exec(command, (error, stdout, stderr) => {
    console.log(`stdout: ${stdout}`)
    console.log(`stderr: ${stderr}`)
    if (error !== null) {
      console.log(`Error ${error}`)
    } else if (sendRes === false) {
    } else if (typeof callback === 'function') {
      callback()
    } else {
      res.send(stdout + stderr)
    }
  })
}
app.get('/arp', (req, res) => {
  console.log('we have a working signal!')
  executeCommand(arpSweepCommand, req, res, false, function () {
    fs.readFile('command_output/arpedHosts.txt', 'utf-8', (error, data) => {
      if (error !== null) {
        res.send(error)
      } else {
        res.send(data)
      }
    })
  })
})

я столкнулся с новой проблемой:
при нажатии arpButton загрузчик появляется, но через 10 секунд (время, выделенное команде в arpSweep.sh до уничтожения netdiscover), кажется, не имеет значения, и загрузчик, кажется, остается там навсегда.
и на сервере я ловлю следующую ошибку.

error: Error can't execute command './arpSweep.sh'

Ответы [ 2 ]

0 голосов
/ 19 марта 2019

Проблема в том, что executeCommand является асинхронным (используется child_process.exec), поэтому вы читаете содержимое файла ДО того, как оно было написано, и поэтому вам нужно нажать кнопку еще раз, чтобы увидеть содержимое в следующем запросе. , Посмотрите пример здесь и как сделать его похожим на синхронизацию с promisify и async/await: https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback

Примерно так (не проверено):

const exec = util.promisify(require('child_process').exec);

async function executeCommand (command, req, res, sendRes = true) {
  return exec(command, (error, stdout, stderr) => {
    console.log(`stdout: ${stdout}`)
    console.log(`stderr: ${stderr}`)
    if (error !== null) {
      console.log(`Error ${error}`)
    } else if (sendRes === false) {
    } else {
      res.send(stdout + stderr)
    }
  })
}

и затем в вашем обработчике:

await executeCommand(arpSweepCommand, req, res, false);
0 голосов
/ 19 марта 2019

проблема для меня в том, что информация не добавляется автоматически к commandOutput

Проблема, с которой вы столкнулись, заключается в том, что браузер не знает, как append json (я полагаю, это не всегда ответ json). Попробуйте добавить responseText вместо data:

success: function (data, status, xhr) {
  console.log(data)
  commandOutput.append(xhr.responseText + '\r\n')
}

Что касается загрузчика - с ним все в порядке, может быть, вам просто нужно скрыть его не на success, а на complete обратном вызове.

В этой части:

executeCommand(arpSweepCommand, req, res, false)
fs.readFile('command_output/arpedHosts.txt', 'utf-8', (error, data) => {

Вы вызываете executeCommand в асинхронном режиме, поэтому вы не можете быть уверены, что выходные данные получены из текущего вызова (это, вероятно, является ядром проблемы, когда вам нужно дважды щелкнуть). Поэтому вы должны переместить reading file часть кода внутри exec обратного вызова внутри executeCommand метода следующим образом:

function executeCommand (command, req, res, cb) {
  exec(command, (error, stdout, stderr) => {
    console.log(`stdout: ${stdout}`)
    console.log(`stderr: ${stderr}`)
    if (error !== null) {
      console.log(`Error ${error}`)
    } else {
      if (typeof cb === 'function') {
        cb()
      } else {
        res.send(stdout + stderr)
      }
    }
  }
}

И

executeCommand(arpSweepCommand, req, res, () => {
  fs.readFile('command_output/arpedHosts.txt', 'utf-8', (error, data) => {
    if (error) {
      res.send(error)
    } else {
      res.send(data)
    }
  })
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...