2017-06-05 104 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