2013-02-09 5 views
2

Я использую fakeweb модуль, который переписывает узла http.request с помощью следующей функции:Перезапись http.request с EventEmitter

var old_request = http.request; 

http.request = function(options, callback){ 
    var rule = match_rule(options); 
    if(rule){ 
     var res = new events.EventEmitter(); 
     res.headers = rule.headers || {'Content-Type': 'text/html'}; 
       return {end: function(){ 
      callback(res); 
      res.emit('data', rule.body || ''); 
      res.emit('end'); 
      } 
     }; 
    } else { 
     return old_request.call(http, options, callback); 
    } 
}; 

Моя проблема заключается в том, что я получаю ошибку: TypeError: Object #<Object> has no method 'on' из следующего кода в другом файле:

var req = proto.request(options, function (res) { ... }); 
req.on('error', function (err) { 
     err.success = false; 
     settings.complete(err); 
    }); 

Я думаю, что моя проблема не возникает, потому что это уже не EventEmitter, хотя я могу ошибаться. Как я могу успешно перезаписать http.request, не получив эту проблему?

Фон: Я использую версию узла 0.8.2. Запрос НПМ версия 2.12.0

Update (11 февраля 2013): Я хочу, чтобы предоставить некоторую информацию о том, где http.request вызывается, так что я могу быть более конкретным о том, что нужно и что вызывает ошибки. Вот где она называется:

var proto = (options.protocol === 'https:') ? https : http;    
var req = proto.request(options, function (res) { 
    var output = new StringStream();     
    switch (res.headers['content-encoding']) { 
     case 'gzip': 
      res.pipe(zlib.createGunzip()).pipe(output); 
      break; 
     case 'deflate': 
      res.pipe(zlib.createInflate()).pipe(output); 
      break; 
     default: 
      // Treat as uncompressed string 
      res.pipe(output); 
      break; 
    } 

    output.on('end', function() { 
     if (settings.cookieJar && res.headers['set-cookie']) { 
      var cookies = res.headers['set-cookie']; 
      for (var i = 0; i < cookies.length; i++) { 
       settings.cookieJar.set(cookies[i]); 
      } 
     } 

     if (res.statusCode >= 300 && res.statusCode < 400) { 
      if (settings.maxRedirects > settings.nRedirects++) { 
       // Follow redirect            
       var baseUrl = options.protocol + '//' + ((proxy) ? options.headers['host'] : options.host), 
        location = url.resolve(baseUrl, res.headers['location']);      
       request(location, settings);         
      } else { 
       var err = new Error('Max redirects reached.'); 
       err.success = false; 
       settings.complete(err); 
      } 
     } else if (res.statusCode >= 400) { 
      var err = new Error(output.caught); 
      err.success = false; 
      err.code = res.statusCode; 
      settings.complete(err);    
     } else {         
      settings.complete(null, output.caught, res); 
     } 
    }); 
}); 
req.on('error', function (err) { 
    err.success = false; 
    settings.complete(err); 
}); 

if (data) { req.write(data); } 

req.end(); 
+0

возвращаемое значение в 'если (правило) {'block is not EventEmitter – Chad

+0

Да, как я мог правильно вернуть EventEmitter? – babonk

+0

Зависит от того, что вы хотите испустить. Вы должны называть 'req.end()', и вы получите событие 'data', а затем событие' end'. Так работает библиотека. Поскольку вызов никогда не производится, вы никогда не получите сообщение об ошибке. Вы действительно должны объяснить свою конечную цель здесь. – Chad

ответ

0

EDIT

Если вы хотите запрос действовать точно так же, только без приложения на самом деле ударяя сервер запроса, то попробуйте использовать nock, которые будут перехватывать запросы вы определить и вернуть данные, которые вы определяете.



Оригинал Ответ:

Я думаю, что вы ищете что-то больше, как это:

var old_request = http.request; 

http.request = function(options, callback){ 
    var rule = match_rule(options); 
    if(rule){ 
     var res = new events.EventEmitter(), 
      req = new events.EventEmitter(); 
     res.headers = rule.headers || {'Content-Type': 'text/html'}; 
     req.end = function(){ 
      if(callback) callback(res); 
      res.emit('data', rule.body || ''); 
      res.emit('end'); 
     }; 
     return req; 
    } else { 
     return old_request.call(http, options, callback); 
    } 
}; 
+0

Эй, когда я это сделаю, я получаю новую ошибку: 'TypeError: Object # не имеет метода 'pipe'', вызванного' var req = http.request (options, function (res) {res.pipe (output);}); ' – babonk

+0

, потому что' req' обычно является записываемым потоком, а не только «EventEmitter»; как я уже говорил, прежде чем я не могу помочь вам, не зная, какова ваша конечная цель, я просто догадываюсь. Скажите мне, что вы хотите, и я могу вам помочь, но это звучит как проблема, которую вы должны публиковать на fakeweb, если это то, что вы используете. – Chad

+0

Я пытаюсь заставить Fakeweb работать с узлом, создав поддельный http.request, который выглядит так же, как и в узле. Это моя единственная цель. Я подумал, что, может быть, несколько небольших хаков, подобных тем, которые вы предложили, получили бы это «шарлатанство», как старая утка http.request. – babonk

Смежные вопросы