繁体   English   中英

Express / NodeJS针对同一路由的多个mysql查询

[英]Express/NodeJS multiple mysql queries for the same route

在一个用express / nodejs编写的博客中,我试图在单个文章页面中同时显示该文章(工作正常)和一组2篇推荐文章。 不幸的是,正如您在代码的注释位中看到的那样,它不起作用(无法两次渲染同一模板)

在这种情况下最好的方法是什么?

<!-- language: lang-js -->
router.get('/*', function(req, res, next) {

var slug=req.url.replace(/^\//,'').replace(/\/$/,'');
var bg = getRandomInt(5);

if(slug==''){
    connection.query('SELECT * FROM `pages` WHERE NOT slug = "about"', function (error, results, fields) {
res.render('index', { title: title, year: year, bg:bg, pages: results });
    });

}else{
    connection.query('SELECT * FROM `pages` where slug=?', [slug], function (error, results, fields)
             {
        if(results.length){ 

            res.render('page', { title: results[0].title, page:results[0] });
        }else{
            console.log(req);
            res.render('error',{url: 'http://'+req.headers.host+req.url});
        }
    });
    /* not working apparently you can't send the header of the template twice umhh
    connection.query('SELECT * FROM `pages` ORDER by RAND () LIMIT 2',  function (error, random, fields)
             {
                res.render('page', { pages:random}); 

             });
    */

}
 });

您不能两次渲染页面,否则会出现错误:将标头发送到客户端后无法设置标头

您需要做的是获取当前文章和推荐的页面,并在获得两个查询的结果后呈现该页面。

为了实现这一点,我使用了: Promise.all ,然后执行了一个res.render

router.get('/*', async (req, res, next) => {

    const slug = req.url.replace(/^\//, '').replace(/\/$/, '');
    const bg = getRandomInt(5);

    if (slug == '') {
        const results = await query('SELECT * FROM `pages` WHERE NOT slug = "about"');

        return res.render('index', {
            title: title,
            year: year,
            bg: bg,
            pages: results
        });

    }

    // Get current article and recommended pages
    // Promise.all returns an array where each entry has
    // the resolved value of the promise passed at that index
    const [article, recommended] = await Promise.all([
        query('SELECT * FROM `pages` where slug=?', [slug]),
        query('SELECT * FROM `pages` ORDER by RAND () LIMIT 2')
    ]);


    if (article.length) {

        // Render the article & recommended pages at once.
        res.render('page', {
            title: article[0].title,
            page: article[0],
            pages: recommended 
        });

    } else {
        console.log(req);
        res.render('error', {
            url: 'http://' + req.headers.host + req.url
        });
    }

});

// Query helper
// You can use promisify...
function query(statement, placeholders = []) {

    return new Promise((resolve, reject) => {

        connection.query(query, placeholders, (error, results) => {

            if(err)
                return reject(err);

            resolve(results);

        });
    });

}

您现在拥有的方式

  • 这两个查询将在不相关的时间完成(并调用其回调)
  • res.render将被多次调用,这不起作用,因为它假定所有数据都在一次调用中发送。 因此,它发送HTTP标头,该标头不能发送两次。

根据您的预期进行了更新。 请注意,这会使查询顺序成为顺序,这可能是不希望的。 您将要使用async库来帮助管理同时运行它们和仍然合并结果:

router.get('/*', (req, res, next) => {
  const slug = req.url.replace(/^\//, '').replace(/\/$/, '');
  const bg = getRandomInt(5);

  if (slug == '') {
    return connection.query('SELECT * FROM `pages` WHERE NOT slug = "about"', (error, results, fields) => {
      res.render('index', { title: title, year: year, bg: bg, pages: results });
    });
  } else {
    return connection.query('SELECT * FROM `pages` where slug=?', [slug], (error, results, fields) => {
      if (results.length) {
        return connection.query('SELECT * FROM `pages` ORDER by RAND () LIMIT 2', (error, random, fields) => {
          if (error) {
            // handle error
          }
          // consolidate renders into a single call
          // adjust the template file accordingly
          return res.render('page', { title: results[0].title, page: results[0], pages: random });
        });
      } else {
        console.log(req);
        return res.render('error', { url: 'http://' + req.headers.host + req.url });
      }
    });
  }
});

或者,考虑使用bluebirdasync / await ,这只是另一种样式-为您提供基于节点8+的新选项。 在这一查询中,查询再次在同一时间开始。

const bluebird = require('bluebird');

router.get('/*', async (req, res, next) => {
  try {
    const slug = req.url.replace(/^\//, '').replace(/\/$/, '');
    const bg = getRandomInt(5);
    if (slug == '') {
      const results = await bluebird.fromCallback(cb => connection.query('SELECT * FROM `pages` WHERE NOT slug = "about"', cb));
      return res.render('index', { title: title, year: year, bg: bg, pages: results });
    } else {
      const [results, random] = await Promise.all([
        bluebird.fromCallback(cb => connection.query('SELECT * FROM `pages` where slug=?', [slug], cb)),
        bluebird.fromCallback(cb => connection.query('SELECT * FROM `pages` ORDER by RAND () LIMIT 2', cb))
      ]);
      if (results && results.length) {
        return res.render('page', { title: results[0].title, page: results[0], pages: random });
      } else {
        return res.render('error', { url: 'http://' + req.headers.host + req.url });
      }
    }
  } catch (e) {
    return res.render('error', { url: 'http://' + req.headers.host + req.url });
  }
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM