簡體   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