【问题标题】:How to render rest api call in node.js with express and handlebar or other template engine?如何使用express和handlebar或其他模板引擎在node.js中渲染rest api调用?
【发布时间】:2016-05-17 13:53:33
【问题描述】:

用例

使用 Node.js、Express 和 Handlebars 等模板引擎查询 Wordpress 和 CouchDB 等其他 API 并呈现结果。

我已经走了这么远

var https = require('https');

var express = require('express');
var handlebars = require('express-handlebars')
        .create({ defaultLayout:'main' });

var app = express();
app.engine('handlebars', handlebars.engine);
app.set('view engine', 'handlebars');
app.set('port', process.env.PORT || 3000);
app.set('ip', process.env.IP);

var options = {
  hostname: 'public-api.wordpress.com',
  path: '/rest/v1.1/sites/somesite.wordpress.com/posts/16',
  method: 'GET'
};

app.get('/test', function(req, res) {
  https.request(options, function(restRes) {
    console.log('STATUS: ' + restRes.statusCode);
    res.render('home', { "title": "Test" }); // This code works.
    restRes.on('data', function (jsonResult) {
//      res.render('home', { "title": "Test" }); This code (after removing the line above) does not work.
      console.log('BODY: ' + jsonResult);
    });
  }).end();
});

app.listen(app.get('port'), app.get('ip'), function(){
  console.log( 'Express started on http://' + app.get('ip') + ": " +
    app.get('port') + '; press Ctrl-C to terminate.' );
});

此代码有效,并且 jsonResult 在控制台上显示正确。在restRes.on('data', function (jsonResult) 回调中移动res.render('home', { "title": "Test" }); 行会引发错误。

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11)
    at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:718:10)
    at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:163:12)
    at res.render.done (/home/ubuntu/workspace/node_modules/express/lib/response.js:957:10)
    at Immediate._onImmediate (/home/ubuntu/workspace/node_modules/express-handlebars/lib/utils.js:26:13)
    at processImmediate [as _immediateCallback] (timers.js:374:17)

我是否监督一个明显的错误?如何以正确的方式做到这一点?

【问题讨论】:

    标签: javascript node.js rest express


    【解决方案1】:

    错误是不言自明的,即当响应已发送时,您无法设置标头。由于以下原因可能会发生错误

    原因 1

    以下失败,因为您尝试多次发送响应。

    //the following lines send the response 
    res.render('home', { "title": "Test" }); // This code works. 
    
    restRes.on('data', function (jsonResult) {
    //you have already send the response above, hence the error
    res.render('home', { "title": "Test" }); This code (after removing the line above) does not work.
      console.log('BODY: ' + jsonResult);
    });
    

    原因 2

    这失败并显示错误,因为.on('data') 被多次调用(取决于响应的大小),这是因为数据以块的形式返回,因此,您尝试多次res.render

    restRes.on('data', function (jsonResult) {
       res.render('home', { "title": "Test" }); 
       console.log('BODY: ' + jsonResult);
    });
    

    可能的解决方案

    您需要使用.on('data') 接收块并在此处构建整个响应,然后使用.on('end') 执行res.render 与完整响应。如下:

    var body = '';
    //use the chunks to build the whole response into body variable
    restRes.on('data', function (chunk) {
       body += chunk; 
    });
    
    //this is called when the request is finished and response is returned
    //hence, use the constructed body string to parse it to json and return
    restRes.on('end', function () {
       console.log('whole response > ' + body); 
       var jsonObject = JSON.parse(body);
       res.render('home', {data:jsonObject}); 
       //in your view use the data that is json object.
    });
    

    另一种可能的解决方案 您可以将返回到 .on('data') 的块连接起来,而不是将它们推送到一个数组中,然后在 .on('end') 中加入将构造响应正文的数组元素,然后将其解析为 JSON,然后返回它。示例如下:

    var body = [];
    restRes.on('data', function(chunk) {
      body.push(chunk);
    });
    
    restRes.on('end', function() {
      //joined the chunks 
      var result = JSON.parse(data.join(''))
      res.render('home', {data: result}); 
    });
    

    【讨论】:

    • 感谢 Raf。现在一切正常。只是一个额外的小问题。我没有找到/理解相应的文档。 Node.js v5.5.0 Documentation 没有命名“数据”事件。我在哪里可以找到文档?
    • 除了这一点 nodejs.org/api/http.html#http_class_http_clientrequest 我在 Node.js 文档中也找不到任何相关信息。我使用我之前在 Can't set header ... 方面的经验回答了您的问题。您也许可以在 Google 上找到有关 Node.js 请求如何工作的教程。
    • 是的,“Google”对此说了一些话,但仍然觉得在 Node.js 文档中找不到记录的“数据”和“结束”事件感到不舒服。
    • 在这种情况下,有人关心:https.request(options, function(restRes)docs 说“可选的回调参数将被添加为‘response’事件的一次性监听器”。 response argument 是一个 http.IncomingMessage,它实现了 ReadableStream,其中解释了事件“数据”和“结束”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    相关资源
    最近更新 更多