javascript - Node.js 发送后无法发送 header

标签 javascript node.js 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
            });
        });
    });
});

变更摘要:

  1. parseString() 操作移到 request() 回调中。
  2. 完全摆脱共享 EventEmitter 的使用。
  3. 为两个异步操作添加错误处理。

如果出于某种原因,您需要或想要在代码中使用 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
            });
        });
    });
});

关于javascript - Node.js 发送后无法发送 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45639646/

相关文章:

javascript - 带有 Ember CLI 的 polymer

javascript - 在我进行第二次提交后,每当我尝试获取登录页面或注册页面时,都会收到 404 错误

node.js - 让 webpack 热更新在我的同构网络应用程序中正常工作

mysql - 如何在node js中使用mysql FIND_IN_SET?

javascript - Webpack 加载器顺序行为不当

javascript - 网站上的图像裁剪并与水印结合

javascript - 处理 ajax 和生成超出原型(prototype)设计的 html 的最佳方法是什么

node.js - 使用 Node.js 进行 IPv6 多播

javascript - 从 Google 电子表格中获取两个日期之间的数据

javascript - 本地模块node.js :can't load files other than index. js