Ошибка с заголовком HTTP при отправке дважды одного и того же запроса - PullRequest
0 голосов
/ 18 сентября 2018

Привет! Я делаю очень простой API, используя NodeJS, ExpressJS и MySQLJ.У меня есть небольшая форма, которая делает запрос login запрос к серверу.Проблема в том, что когда я пытаюсь выполнить один и тот же запрос дважды после завершения первого, сервер отвечает мне: ERR_CONNECTION_REFUSED

. Я использовал это руководство для того, чтобы сделать мой коднемного чище.Я немного изменился, потому что я думаю, что класс делает код чище, чем использование functions.

https://code.tutsplus.com/tutorials/managing-the-asynchronous-nature-of-nodejs--net-36183

Это полный возврат ошибки, которую я имею

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at User.<anonymous> (/home/ismael/Projects/internal_project/app.js:84:9)
    at User.emit (events.js:187:15)
    at Query.<anonymous> (/home/ismael/Projects/internal_project/model/user.js:20:14)
    at Query.<anonymous> (/home/ismael/Projects/internal_project/node_modules/mysql/lib/Connection.js:502:10)
    at Query._callback (/home/ismael/Projects/internal_project/node_modules/mysql/lib/Connection.js:468:16)
    at Query.Sequence.end (/home/ismael/Projects/internal_project/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
    at Query._handleFinalResultPacket (/home/ismael/Projects/internal_project/node_modules/mysql/lib/protocol/sequences/Query.js:139:8)
    at Query.EofPacket (/home/ismael/Projects/internal_project/node_modules/mysql/lib/protocol/sequences/Query.js:123:8)
    at Protocol._parsePacket (/home/ismael/Projects/internal_project/node_modules/mysql/lib/protocol/Protocol.js:278:23)

Это мой основной javascript, где я определяю основную структуру моего простого приложения.В журнале я вижу, что второй запрос - это успешный ответный вызов, что мне не хватает?

app.post( '/login/', function(req, res){
  user.on('success', function(result){
    logger.debug( '[SUCCESS]' );

    res.cookie('user', { name : result.name, id : result.id  });
    res.setHeader( 'Content-Type', 'application/json' );
    res.status(200).end( JSON.stringify({success : true}) );
  });
  user.on('failure', function(reason){
    logger.debug( '[FAILURE]' );

    res.setHeader( 'Content-Type', 'application/json' );
    res.status(400).send( JSON.stringify({success: false}) );
  });
  user.on('error', function(error){
    // logger.debug( '[ERROR]' );
    //
    // res.setHeader( 'Content-Type', 'application/json' );
    // res.status(500).send( JSON.stringify({ error: 'Internal error' }) );
  });
  user.login( req.body.username, req.body.password );
});

И это метод входа в класс User

login ( username, password ){
    var that = this;

    this.sql.query( "SELECT * FROM user WHERE name = ? AND password = ?", [ username, password ], function(error, result, fields){
      // if ( error ){
      //   that.emit('error', error);
      //   return true;
      // }

      if ( result.length == 0 ){
        that.emit( 'failure' );
        return true;
      }

      if ( result.length >= 1 ){
        that.emit( 'success', result[0] );

        return true;
      }

    });
  }

IЯ использую этот Javascript на лицевой стороне, чтобы получить все значения из формы входа и отправить его в API.

main.js

(function(){
  var _loginForm = {},
      _loginUsername = {},
      _loginPassword = {},
      _loginConfig = {
        url : '/login/',
        method : 'POST'
      },
      _loginRequest = new XMLHttpRequest();

  var
  _onLoginRequest = function(){
    console.log( this );

    if ( this.readyState == 4 ){
      JSON.parse(this.responseText)
    }
  },
  _onLoginSubmit = function(evt){
    evt.preventDefault();

    _loginRequest.onreadystatechange = _onLoginRequest;
    _loginRequest.open( _loginConfig.method, _loginConfig.url, true );
    _loginRequest.setRequestHeader( 'Content-Type', 'application/json' );
    _loginRequest.send(JSON.stringify({
      username : _loginUsername.value,
      password : _loginPassword. value
    }));
  },
  _onDomLoad = function(evt){
    _loginForm = document.getElementById( 'login-form' );
    _loginUsername = document.getElementById( 'username' );
    _loginPassword = document.getElementById( 'password' );

    _loginForm.addEventListener( 'submit', _onLoginSubmit );
  };

  document.addEventListener( 'DOMContentLoaded', _onDomLoad );

})();

Спасибо ввперед.

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Создайте объект User внутри app.post вызова API вместо создания его глобально.

0 голосов
/ 18 сентября 2018

Вы регистрируете обработчики событий для каждого запроса.Проблема в том, что вы впоследствии не удаляете ни один из обработчиков запросов.

Например, если вы выполнили 10 запросов POST к конечной точке входа в систему, а затем сделали 11-е.Если 11-е число прошло успешно, событие success запускается для текущего запроса, но также для всех остальных 10.

Причина, по которой вы получаете Cannot set headers after they are sent to the client, заключается в том, что прослушиватель событий запускается для HTTPзапрос, который уже выполнен.

Решение состоит в том, чтобы создать это другоеEventListener не хорошая модель для вызова функций и получения результатов.EventListener хорош для вещей, которые могут срабатывать много раз.В этом случае вы этого не хотите, вам нужен только 1 успех или 1 сбой на запрос.

Правильная модель для этого:

A) Простой вызов функции.Он может возвращать информацию, связанную с его успехом, и выдавать исключение в случае неудачи.

B) Вернуть обещания.Разрешите их, если вход был успешным, отклоните их, если нет.

C) Используйте async / await.Опять же: верните result, если он был успешным, если нет, выведите ошибку.

D) Используйте шаблон обратного вызова, который вы уже используете с express.Поэтому передайте обратный вызов с параметрами err и result.

Последний вариант может быть предпочтительнее, поскольку вы работаете с платформой, которая не поддерживает Promises и хорошо выполняет асинхронное / ожидание.

...