2017-06-05 107 views
0

我最近开始重构旧的回调 - 地狱路由以使用承诺。(注:重构不完成这么一些下面的代码是丑陋的)Express.js:res.render()在包装在承诺链中时不发送数据

这样做打破了我的res.render()功能。

  • 我正在使用EJS作为我的渲染引擎。
  • 我的许多承诺链都是基于MongoDB/Mongoose查询构建的。

基本的应用程序结构是一个复杂的调查/测验,将用户分为不同的类别。它存储他们的信息并在最后呈现一个自定义的EJS页面。以下是最后通话的工作原理,基本上如下:

  mongoose.model('Result') 
      .findOne({quizId: req.query.id}) 
      .then(getPageData) 
      .then(renderPage) 
      .catch(errorHandler) 

理论上足够简单。

相关功能:

let getPageData = (mongooseResult) => { 

     let resultsPage; 
     let analyticsData; 

     if (mongooseResult.answers.section1.question1.answer != null && mongooseResult.answers.section1.question1.answer != undefined){ 
      let resultsPage = WP.getPage(wp_pages_data, 'slug', mongooseResult.coreFit); 
      let analyticsData = { 
      quizId: mongooseResult.quizId, 
      coreFit: mongooseResult.coreFit, 
      secondFit: mongooseResult.secondFit, 
      degree: mongooseResult.answers.section1.question1.answer, 
      year: mongooseResult.answers.section1.question2.answer, 
      concentration: mongooseResult.answers.section1.question3.answer, 
      views: mongooseResult.views, 
      } 

     mongooseResult.views++; 
     mongooseResult.save(); 

     return [resultsPage, analyticsData, mongooseResult]; 
     } else { 
     throw new Error('S1Q1 IS UNDEFINED'); 
     } 
    }; 
    let renderPage = ([resultsPage, analyticsData, mongooseResult]) => { 
     if (resultsPage != null && resultsPage != undefined){ 

     // WHY IS MY RENDER NOT WORKING??? 
     res.render('templates/' + mongooseResult.coreFit, Object.assign({}, WP.get_WP_data(resultsPage), getPartials(mongooseResult.modules), analyticsData), (err, html) => {if (err) console.log(err); else res.send(html);}); 
     } else { 
     throw new Error('GETTING PAGE DATA RETURNED UNDEFINED'); 
     } 
    }; 

传入的请求首先被路由到/submit POST路线 - 它操作的一些数据,把它存储所有的数据库,然后做res.redirect()/results?id=12345 GET路线,其运行逻辑以上。

有什么好奇的是render()实际上是火灾;回调((err, html) => {if (err) console.log(err); else res.send(html);})将呈现的HTML发送到如果您第二次启用路由。

完成调查不会产生回应;但是它会将我们所有的信息成功存储在数据库中,而console.logs则是客户端请求应该重定向到的ID。使用这个生成的ID/URL打字获取路线,字面上通过复制粘贴它,渲染就好。

交换渲染的简单res.send('wtf')工程 - 实际的响应发送到客户端。 (在这种情况下字符串'wtf'...)

响应只是不发回数据。我不明白。有任何想法吗?

UPDATE: 奇怪的是,手动击打路线VS从我早期的POST请求重定向产生一个简单的res.send('wtf mate')不同的结果。

击中GET路由和传递一个先前已有的ID手动将req.query:enter image description here

击中GET路线从现有POST请求中的呼叫res.redirect() AFTER:enter image description here

这可能是更快速的请求类型不匹配问题?为什么res.redirect('/results?id=someString')调用会改变URL并返回一个字符串/ HTML?

+0

为什么你传递匿名函数作为最后一个参数? 'res.render'并发送给客户端。我不认为有必要做额外的'res.send'。 – num8er

+0

你是对的 - 在这种情况下仅用于调试;我想知道是否明确添加额外的回调函数是否有帮助 - 或者在幕后吞下了秘密的“err”。 – Zfalen

+0

由于您使用的是像'mongooseResult.save()'这样的代码,您确定'POST/submit'实际上是在数据库保存/更新之前实际_waits_在重定向之前完成的吗? – robertklep

回答

1

让我们试着通过测试代码部分来调试问题。

我有一些线索,其中之一是'templates/' + result.coreFit没有模板。
如果templates文件夹中存在具有相同名称的文件夹,请尝试检查coreFit值。

试试这个代码,并告诉我,如果它的工作:

const 
    _ = require('lodash'), 
    mongoose = require('mongoose'); 

const getQuizResultById = quizId => { 
    return new Promise((resolve, reject) => { 
     const 
      Result = mongoose.model('Result'), 
      query = { 
       quizId 
      }; 

     Result 
      .findOne(query) 
      .then(resolve) 
      .catch(reject); 
    }); 
}; 

const getPageData = result => { 
    if (_.get(result, 'answers.section1.question1.answer')) { 
     let resultsPage = WP.getPage(wp_pages_data, 'slug', result.coreFit); 
     let 
     analyticsData = _.pick(result, ['quizId', 'coreFit', 'secondFit', 'views']); 
     analyticsData.degree = _.get(result, 'answers.section1.question1.answer'); 
     analyticsData.year = _.get(result, 'answers.section1.question2.answer');   
     analyticsData.concentration = _.get(result, 'answers.section1.question3.answer'); 

     result.views++; 
     result.save(); 

     return [resultsPage, analyticsData, result]; 
    } 

    throw new Error('S1Q1 IS UNDEFINED'); 
} 

const renderPage = ([resultsPage, analyticsData, result], res) => { 
    if (resultsPage) { 
     return res.render(
      'templates/' + result.coreFit, 
      Object.assign({}, WP.get_WP_data(resultsPage), getPartials(result.modules), analyticsData), 
      (err, html) => { 
       if (err) { 
        console.log(err); 
        return res.status(500).send('Ooopsss...'); 
       } 
       res.send(html); 
      }); 
    } 

    throw new Error('GETTING PAGE DATA RETURNED UNDEFINED'); 
}; 

router.get('/results', (req, res) => { 
    getQuizResultById(req.query.id) 
     .then(getPageData) 
     .then(data => { 
      renderPage(data, res); 
     }) 
     .catch(errorHandler); 
}); 
+1

感谢您的回复,@ num8er!事实证明,在重构过程中,我的客户端监督是可怕的。查看Lars上面的答案 - 关键线索是我的网址栏在提交最终调查时作为重定向的一部分时,如何在GET路径中重新路由....由于99%的重构是完全服务器端的,方 – Zfalen

2

根据您的更新,这听起来像你res.send()呼叫正在奇怪的解释在客户端上。 POST请求不应该影响URL栏,除非你明确告诉它 - 你检查了客户端最初发送这个请求的位置吗?

我的猜测 - 既然你说上面发布的路由代码是从前一个POST路由的res.redirect()中选择的 - 是否有客户端逻辑预计response对象是一个URL字符串,并且触及GET第一次通过您的重定向路由进入这个响应对象。以便客户端试图将大量的HTML插入到URL栏中。

在这种情况下,手动击中GET路线,就像你说的,只会默认呈现从res.render()的HTML - 但是你从res.redirect()最初击中时可能不会。

+0

DOH!你钉了它....这是我的客户端AJAX的一部分: '成功:(res)=> {window.location = res; “所以,是的,你是对的。由于'res.render()'返回一个HTML字符串,所以URL栏不知道如何处理它。但默认的GET行为需要HTML - 所以手动ping路由的行为是正确的。我不是做'res.redirect()',而是做了一个'res.send('results?id = 12345')' - 它将客户端重定向到我的GET路由,这一切都与世界一切!谢谢! – Zfalen