2016-09-19 177 views
-1

我正在研究一个小节点& express.js应用程序。 我在app.get('/lastName/:lastName',(req,res) =>{...}); 发现如果我使用:Node/Express.js:发送后不能设置标题

res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)}); 

它总是res.format({...}); 冲突它给了我一个错误:

throw new Error('Can\'t set headers after they are sent.'); 

当我单独使用它们,在http://localhost:3000/lastName/Smith我能得到正确的视图。如果我只用res.format({...});我还可以通过获得正确的API反馈:

curl -X GET -H "Accept:application/xml" "http://localhost:3000/lastName/Smith" 

不过,我不能在同一时间,这是冲突与任务要求使用它们。 有人可以给我一些线索吗?非常感谢!请参阅下面的代码:

'use strict'; 
const express = require('express'); 
const _= require('underscore'); 
const handlebars = require('express-handlebars'); 
const employees = require('./employeeModule.js'); 
const bodyParser = require('body-parser'); 
const app = express(); 

app.engine('handlebars', 
    handlebars({defaultLayout: 'main'})); 

app.set('view engine', 'handlebars'); 

app.use(express.static(__dirname + '/public')); 
app.use(bodyParser.urlencoded({extended:false})); 
app.use(bodyParser.json()); 

// GET request to the homepage 
app.get('/', (req, res) => { 
    res.render('home'); 
}); 
app.get('/addEmployee',(req,res) => { 
    res.render('newEmployee'); 
}); 
//..........................Problem here......................... 
app.get('/id/:id',(req,res)=>{ 
    let paramsId = parseInt(req.params.id); 
    //res.render('employeeList',{data:employees.lookupById(paramsId)}); 
    //res.send(employees.lookupById(paramsId)); 
    res.format({ 
     'application/json':() => { 
      res.json(employees.lookupById(paramsId)); 
     }, 
     'application/xml':() => { 
      let employeeXml = 
       '<?xml version="1.0"?>\n<employees>\n' + 
       employees.lookupById(paramsId).map((e)=>{ 
        return ' <employee id="' + e.id + '">' + 
         '<firstName>' + e.firstName + '</firstName>'+ '<lastName>' + e.lastName + '</lastName>' + '</employee>'; 
       }).join('\n') + '\n</employees>\n'; 
      res.type('application/xml'); 
      res.send(employeeXml); 
     }, 
     'text/html':() => { 
      let employeeHtml = '<ul>\n' + 
       employees.lookupById(paramsId).map((e)=>{ 
        return ' <li>' + e.id + ' - ' + 
         e.firstName + ' - ' + e.lastName+'</li>'; 
       }).join('\n') + '\n</ul>\n'; 

      res.type('text/html'); 
      res.send(employeeHtml); 
     }, 
     'text/plain':() => { 
      let employeeText = 
       employees.lookupById(paramsId).map((e)=>{ 
        return e.id + ': ' + e.firstName + e.lastName; 
       }).join('\n') + '\n'; 
      res.type('text/plain'); 
      res.send(employeeText); 
     }, 
     'default':() => { 
      res.status(404); 
      res.send("<b>404 - Not Found</b>"); 
     } 
    }); 

}); 
//..........................Problem here......................... 
app.get('/lastName/:lastName',(req,res) =>{ 
    let paramsLastName = req.params.lastName; 
    res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)}); 
    res.format({ 
     'application/json':() => { 
      res.json(employees.lookupByLastName(paramsLastName)); 
     }, 
     'application/xml':() => { 
      let employeeXml = 
       '<?xml version="1.0"?>\n<employees>\n' + 
       employees.lookupByLastName(paramsLastName).map((e)=>{ 
        return ' <employee id="' + e.id + '">' + 
         '<firstName>' + e.firstName + '</firstName>'+ '<lastName>' + e.lastName + '</lastName>' + '</employee>'; 
       }).join('\n') + '\n</employees>\n'; 
      res.type('application/xml'); 
      res.send(employeeXml); 
     }, 
     'text/html':() => { 
      let employeeHtml = '<ul>\n' + 
       employees.lookupByLastName(paramsLastName).map((e)=>{ 
        return ' <li>' + e.id + ' - ' + 
         e.firstName + ' - ' + e.lastName+'</li>'; 
       }).join('\n') + '\n</ul>\n'; 

      res.type('text/html'); 
      res.send(employeeHtml); 
     }, 
     'text/plain':() => { 
      let employeeText = 
       employees.lookupByLastName(paramsLastName).map((e)=>{ 
        return e.id + ': ' + e.firstName + e.lastName; 
       }).join('\n') + '\n'; 
      res.type('text/plain'); 
      res.send(employeeText); 
     }, 
     'default':() => { 
      res.status(404); 
      res.send("<b>404 - Not Found</b>"); 
     } 
    }); 
}); 

app.post('/data',function (req,res) { 
    let bodyData = req.body; 
    let bodyDataFirstName = bodyData.firstName; 
    let bodyDataLastName = bodyData.lastName; 
    employees.addEmployee(bodyDataFirstName,bodyDataLastName); 
    res.redirect('/lastName/'+bodyDataLastName); 
}) 
app.get('/api/employees',(req,res) =>{ 
    res.format({ 
     'application/json':() => { 
      res.json(employees.getAllEmployee()); 
     }, 
     'application/xml':() => { 
      let employeeXml = 
       '<?xml version="1.0"?>\n<employees>\n' + 
       employees.getAllEmployee().map((e)=>{ 
        return ' <employee id="' + e.id + '">' + 
         e.firstName + e.lastName + '</employee>'; 
       }).join('\n') + '\n</employees>\n'; 
      res.type('application/xml'); 
      res.send(employeeXml); 
     }, 
     'text/html':() => { 
      let employeeHtml = '<ul>\n' + 
       employees.getAllEmployee().map((e)=>{ 
        return ' <li>' + e.id + ' - ' + 
         e.firstName + ' - ' + e.lastName+'</li>'; 
       }).join('\n') + '\n</ul>\n'; 

      res.type('text/html'); 
      res.send(employeeHtml); 
     }, 
     'text/plain':() => { 
      let employeeText = 
       employees.getAllEmployee().map((e)=>{ 
        return e.id + ': ' + e.firstName + e.lastName; 
       }).join('\n') + '\n'; 
      res.type('text/plain'); 
      res.send(employeeText); 
     }, 
     'default':() => { 
      res.status(404); 
      res.send("<b>404 - Not Found</b>"); 
     } 
    }); 
}); 


app.use((req, res) => { 
    res.status(404); 
    res.render('404'); 
}); 


app.listen(3000,() => { 
    console.log('http://localhost:3000'); 
}); 


/* 
curl -X GET "http://localhost:3000/api/employees" 

curl -X GET -H "Accept:application/json" "http://localhost:3000/api/employees" 

curl -X GET -H "Accept:application/xml" "http://localhost:3000/api/employees" 

curl -X GET -H "Accept:text/html" "http://localhost:3000/api/employees" 

curl -X GET -H "Accept:text/plain" "http://localhost:3000/api/employees" 

*/ 
/* 
curl -X GET "http://localhost:3000/api/employees" 

curl -X GET -H "Accept:application/json" "http://localhost:3000/lastName/Smith" 
curl -X GET -H "Accept:application/xml" "http://localhost:3000/lastName/Smith" 

curl -X GET -H "Accept:application/json" "http://localhost:3000/id/2" 
curl -X GET -H "Accept:application/xml" "http://localhost:3000/id/2" 

*/ 

回答

0

您正在向同一请求发送两次响应。

当您的代码尝试向相同的请求发送两个响应时,会导致您收到的错误消息。所以,你必须删除代码中所有可能发生的地方。

在您的app.get('/lastName/:lastName', ...)处理程序中,您首先调用res.render(),然后再尝试执行res.send()。但是,您拨打res.render()的方式对该请求的响应已通过该呼叫发送,因此您不能再次呼叫res.send()res.json(),因为它会尝试向同一请求发送另一个响应,并且会触发该错误你看到的消息。

如果您只是想渲染HTML,然后将该呈现的HTML用作稍后发送的响应的一部分,那么您需要使用其他形式的res.render(),并在其中传递回调并调用它返回HTML,然后您可以稍后发送。

请参阅文档res.render()了解如何使用回调选项来获取HTML,而不将其作为响应发送,以便稍后在发送您想要发送的响应时使用它。

总体方案是这样的:

app.get('/lastName/:lastName',(req,res) =>{ 
    res.render(file, options, function(err, html) { 
     if (!err) { 
      // response has not been sent yet 
      // put your res.format() code here and use the above html argument 
     } 
    }) 
}) 
+0

为什么downvote?这显然是OP代码中的一个问题。 – jfriend00

0

你发送一个响应的两倍。

您的res.render呈现employeeList然后发送它作为回应。之后,您将尝试发送另一个不允许的响应,并且不符合请求响应周期。

此外,您使用的模板引擎来渲染页面:

let paramsLastName = req.params.lastName; 
res.render('employeeList',{data:employees.lookupByLastName(paramsLastName)}); 

然后尝试手动在这里做它:

'text/html':() => { 
      let employeeHtml = '<ul>\n' + 
       employees.lookupById(paramsId).map((e)=>{ 
        return ' <li>' + e.id + ' - ' + 
         e.firstName + ' - ' + e.lastName+'</li>'; 
       }).join('\n') + '\n</ul>\n'; 

      res.type('text/html'); 
      res.send(employeeHtml); 
     } 

,您可以调用资源。渲染res.format'text/html', 或res.format块之外使用app.render - 它呈现的HTML,但不发送它作为响应。

app.render('index', {data:employees.lookupByLastName(paramsLastName)}, function(err, result) { 
    // result is the resulting html from rendering your data. 
    // save it to some variable to use later or do something with it here 
});