Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Node.js可以';发送邮件头后,不要发送邮件头_Javascript_Node.js_Express - Fatal编程技术网

Javascript Node.js可以';发送邮件头后,不要发送邮件头

Javascript Node.js可以';发送邮件头后,不要发送邮件头,javascript,node.js,express,Javascript,Node.js,Express,我正在尝试制作一个小应用程序,它可以从500px.com(一个照片网站)的rss提要中获取给定用户的照片拇指。我对这一切还比较陌生 在本地测试时,我看到一种我不理解的行为。页面在第一次加载时可以正常加载,但在重新加载时,我会得到“发送后无法发送标题”。从这里的其他答案来看,这似乎通常是由双重回调引起的。我试着把一些if(err)res.send()语句在不同的地方,但它似乎没有解决问题。我还尝试重新配置代码的结构,这似乎也不起作用 有没有比我更有经验的人知道这里发生了什么 var express

我正在尝试制作一个小应用程序,它可以从500px.com(一个照片网站)的rss提要中获取给定用户的照片拇指。我对这一切还比较陌生

在本地测试时,我看到一种我不理解的行为。页面在第一次加载时可以正常加载,但在重新加载时,我会得到“发送后无法发送标题”。从这里的其他答案来看,这似乎通常是由双重回调引起的。我试着把一些
if(err)res.send()语句在不同的地方,但它似乎没有解决问题。我还尝试重新配置代码的结构,这似乎也不起作用

有没有比我更有经验的人知道这里发生了什么

var express = require('express');
var router = express.Router();
var request = require('request');
var parseString = require('xml2js').parseString;
const cheerio = require('cheerio');

var EventEmitter = require('events').EventEmitter;
var body = new EventEmitter();

/* GET home page. */
router.get('/', function(req, res, next) {


  request("https://500px.com/janedoe/rss", function(error, response, data) {
        body.data = data;
        body.emit('update');
  }); 

  body.on('update', function() {

    parseString(body.data, function (err, result) {

        // the stuff below likely isn't relevant to the problem, just some testing

        var photoLink = result.rss.channel[0].item[0].description[0];

        const $ = cheerio.load(photoLink);
        const links = $('img');
        const linkString = links.attr('src').toString();

        // end of area probably not relevant

        res.render('index', { title: 'Express', linkString});

    });



  });

});

module.exports = router;

这里有很多问题。可能导致您询问的特定错误的原因是,每次点击路由时,您都会向EventEmitter对象添加另一个侦听器,因此在第二次点击路由后,您会有两个侦听器,因此当您发射时,您会有两个侦听器被调用,并尝试发送两个响应,其中一个发送到已发送其响应的旧响应对象

这里的核心问题是,您试图在请求中使用模块级变量。这会导致不同请求之间的交叉耦合(这两个请求在处理其请求时都试图潜在地使用相同的发射器对象)。这只是一个竞争条件,当您有多个用户使用您的系统时,它将立即发生

我完全不知道为什么在这里使用
EventEmitter
对象,因为它似乎不需要。当请求收集了所有数据时,您可以只处理最终结果,而不使用EventEmitter。这将修复争用条件和多个处理程序

以下是一种修复方法:

router.get('/', function(req, res, next) {
    request("https://500px.com/janedoe/rss", function(error, response, data) {
        if (error) {
            next(error);
            return;
        }
        parseString(data, function(err, result) {
            if (err) {
                next(err);
                return;
            }
            // the stuff below likely isn't relevant to the problem, just some testing

            var photoLink = result.rss.channel[0].item[0].description[0];

            const $ = cheerio.load(photoLink);
            const links = $('img');
            const linkString = links.attr('src').toString();

            // end of area probably not relevant

            res.render('index', {
                title: 'Express',
                linkString
            });
        });
    });
});
更改摘要:

  • parseString()
    操作移到
    request()回调函数中
  • 完全摆脱共享EventEmitter的使用
  • 在两个异步操作上添加错误处理

  • 如果出于某种原因,您需要或想要在代码中使用
    EventEmitter
    (尽管当前代码没有显示您需要使用它的原因),您必须为正在处理的每个请求创建一个新的事件发射器,并且只将其存储在该特定请求的范围内(而不是在模块级变量中)。这既可以防止飞行中不同请求之间的串扰,也可以防止为同一事件向
    EventEmitter
    对象添加多个侦听器,因为每个请求都有一个单独的
    EventEmitter
    ,而您只向该
    EventEmitter
    对象添加一个侦听器。以下是如何做到这一点:

    /* GET home page. */
    router.get('/', function(req, res, next) {
        // make EventEmitter object for this particular request
        let body = new EventEmitter();
    
        request("https://500px.com/janedoe/rss", function(error, response, data) {
            if (error) {
                next(error);
                return;
            }
            body.data = data;
            body.emit('update');
        });
    
        body.on('update', function() {
    
            parseString(body.data, function(err, result) {
                if (err) {
                    next(err);
                    return;
                }
    
                // the stuff below likely isn't relevant to the problem, just some testing
    
                var photoLink = result.rss.channel[0].item[0].description[0];
    
                const $ = cheerio.load(photoLink);
                const links = $('img');
                const linkString = links.attr('src').toString();
    
                // end of area probably not relevant
    
                res.render('index', {
                    title: 'Express',
                    linkString
                });
            });
        });
    });
    

    您似乎可以将
    body.on('update…
    )中的所有内容移动到请求的回调中。如果请求失败,您还应该进行错误处理。我不知道应用程序的其余部分是什么样子,但这里不需要EventSemiter

    var express = require('express');
    var router = express.Router();
    var request = require('request');
    var parseString = require('xml2js').parseString;
    const cheerio = require('cheerio');
    
    var EventEmitter = require('events').EventEmitter;
    var body = new EventEmitter();
    
    /* GET home page. */
    router.get('/', function(req, res, next) {
      request("https://500px.com/janedoe/rss", function(error, response, data) {
        parseString(data, function (err, result) {
    
          // the stuff below likely isn't relevant to the problem, just some testing
    
          var photoLink = result.rss.channel[0].item[0].description[0];
    
          const $ = cheerio.load(photoLink);
          const links = $('img');
          const linkString = links.attr('src').toString();
    
          // end of area probably not relevant
    
          res.render('index', { title: 'Express', linkString});
    
        });
      }); 
    });
    
    module.exports = router;
    

    您可以在路由处理程序中移动
    EventEmitter
    ,以避免出现这种情况

    简单地划掉这条线:

    var body = new EventEmitter();
    
    并将其粘贴到路线中:

    router.get('/', function(req, res, next) {
    
      var body = new EventEmitter();          // Paste it here
      request("https://500px.com/janedoe/rss", function(error, response, data) {
            body.data = data;
            body.emit('update');
      }); 
    
      // The rest of your code here ...
    
    });
    

    在哪里导入?@jfriend00很好地解释了为什么在他的回答中,我想我已经弄明白了为什么这是错误的方法。谢谢!非常感谢你的解释。所以基本上每次客户端加载页面时,它都会提示一个新的EventEmitter实例——因此,当更新启动时,它会尝试呈现twi对同一个客户端执行一次或多次,但它不能执行?@testingtesting-不完全正确。您的代码只有一个EventEmitter实例,但每次客户端加载页面时,您都会在该实例上添加另一个侦听器。然后当您
    .emit()
    对于它,所有侦听器都会触发,导致它发送多个响应,从而触发您看到的日志消息。此外,您还存在一个漏洞,因为您与所有请求处理程序共享一个
    EventEmitter
    ,因此每当您的服务器为多个用户提供服务时,您都容易受到以下两者之间的串扰/竞争条件的影响n个不同的用户。@testingtesting-我添加了一个示例,通过为每个请求创建一个新的
    EventEmitter
    对象,您可以在代码中安全地使用
    EventEmitter
    。明白了,很有意思。所以实际上问题是,如果我理解的话,我试图在同一个EventEmitter实例上执行多次更新正确地