我试图让所有种类的数据返回到我的作者端点。 如果传递给端点的url不包含查询参数,我希望路由器返回可用作者的完整列表。 如果url包含firstName和lastName参数,我希望控制器找到匹配的作者,并将该数据传回给路由器。
目前,如果我发送的URL为http://localhost:3001/authors或http://localhost:3001/authors?firstName=tom&lastName=dooly , http://localhost:3001/authors?firstName=tom&lastName=dooly收到错误Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 。
谁能告诉我为什么发生这种情况,以及如何解决它?
主要:
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var mongoose = require('mongoose'); var app = express(); var dev_db_url = 'mongodb://localhost:27017/' var mongoDB = process.env.MONGODB_URI || dev_db_url; mongoose.connect(dev_db_url); mongoose.Promise = global.Promise; var db = mongoose.connection; db.on('error', console.error.bind(console, 'MongoDB connection error:')); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); var index = require('./routes/index'); var users = require('./routes/users'); var feedEntries = require('./routes/feedEntries'); var authors = require('./routes/authors'); app.use('/', index); app.use('/users', users); app.use('/feedEntries', feedEntries); app.use('/authors', authors); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not not Found'); err.status = 404; next(err); }); app.use(function(err, req, res, next) { res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; res.status(err.status || 500); res.render('error'); }); module.exports = app;路线:
var express = require('express'); var router = express.Router(); var authorController = require('../controllers/authorController'); authorController.findAuthorsByFirstAndLastName); router.get('/', function (req, res) { if(req.query.firstName||req.query.lastName) { res.send(authorController.findAuthorsByFirstAndLastName(req,res)); }else{ res.send(authorController.author_list(req,res)); } }); module.exports = router;控制器:
var Author = require('../models/author') var async = require('async') exports.author_list = function(req, res, next) { Author.find({},function(err, authors) { if (err){ res.send(err); } return.json(authors); }); }; exports.findAuthorsByFirstAndLastName = function (req, res, next){ var query = {} if(req.query.firstName||req.query.lastName) { query = {$or:[{firstName:{$regex: req.query.firstName, $options: 'i'}}, {lastName:{$regex: req.query.lastName, $options: 'i'}}]} } else { return res.status(500).send({ error: 'Unable to parse data'}); } var firstName = req.body.firstName; var lastName = req.body.lastName; Author.find(query , function (err, authors) { if(err) { res.send(err); } res.json(authors); }); };I'm trying to make a catch-all of sorts to return data to my Author endpoint. If the url that is passed to the endpoint contains no query parameters, I want the router to return the full list of authors available. If the url contains firstName and lastName parameters, I want the controller to find the authors that match and, pass that data back to the router.
Currently if I send the urls http://localhost:3001/authors or http://localhost:3001/authors?firstName=tom&lastName=dooly, I get an error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
Can anyone tell me why this is happening and how to fix it?
main:
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var mongoose = require('mongoose'); var app = express(); var dev_db_url = 'mongodb://localhost:27017/' var mongoDB = process.env.MONGODB_URI || dev_db_url; mongoose.connect(dev_db_url); mongoose.Promise = global.Promise; var db = mongoose.connection; db.on('error', console.error.bind(console, 'MongoDB connection error:')); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); var index = require('./routes/index'); var users = require('./routes/users'); var feedEntries = require('./routes/feedEntries'); var authors = require('./routes/authors'); app.use('/', index); app.use('/users', users); app.use('/feedEntries', feedEntries); app.use('/authors', authors); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not not Found'); err.status = 404; next(err); }); app.use(function(err, req, res, next) { res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; res.status(err.status || 500); res.render('error'); }); module.exports = app;route:
var express = require('express'); var router = express.Router(); var authorController = require('../controllers/authorController'); authorController.findAuthorsByFirstAndLastName); router.get('/', function (req, res) { if(req.query.firstName||req.query.lastName) { res.send(authorController.findAuthorsByFirstAndLastName(req,res)); }else{ res.send(authorController.author_list(req,res)); } }); module.exports = router;controller:
var Author = require('../models/author') var async = require('async') exports.author_list = function(req, res, next) { Author.find({},function(err, authors) { if (err){ res.send(err); } return.json(authors); }); }; exports.findAuthorsByFirstAndLastName = function (req, res, next){ var query = {} if(req.query.firstName||req.query.lastName) { query = {$or:[{firstName:{$regex: req.query.firstName, $options: 'i'}}, {lastName:{$regex: req.query.lastName, $options: 'i'}}]} } else { return res.status(500).send({ error: 'Unable to parse data'}); } var firstName = req.body.firstName; var lastName = req.body.lastName; Author.find(query , function (err, authors) { if(err) { res.send(err); } res.json(authors); }); };最满意答案
当你在路由中有两个res.[whatever]时,你cannot set headers after they are sent 。 所以你有res.send(functionCallThatAlsoDoesRes.Send) 。 这就是导致错误的原因。
如果您希望路由在请求和响应之间执行多个操作,则可以将它们编写为单独的中间件。 中间件始终采用req , res和next这两个参数(一个函数说明要转到列表中的下一个中间件)。
所以,你可以写:
authorController.findAuthorsByFirstAndLastName = function(req, res, next) { if (!(req.query.firstName || req.query.lastName)) { res.locals.getFullAuthorList = true return next() } else { const query = /* whatever */ Author.find(query, (err, authors) => { if (err) return next(err) res.locals.authors = authors next() }) } } authorController.author_list = function(req, res, next) { if (!res.locals.getFullAuthorList) return next() // if we already have authors we don't need to do anything Author.find({}, (err, authors) => { if (err) return next(err) res.locals.authors = authors next() }) }然后在你的路线中,你会说:
router.get('/', authorController.findAuthorsByFirstAndLastName, authorController.author_list, (req, res) => { res.json({ authors: res.locals.authors }) })如果你以前没有看到res.locals ,它只是响应对象上的一个属性,可供你附加。 它在整个请求/响应周期中保持不变,并为每个新请求清除。
You get cannot set headers after they are sent when you have two res.[whatever]s in your route. So you have res.send(functionCallThatAlsoDoesRes.Send). That's what's causing the error.
If you want a route to take multiple actions between the request and the response, you can write those as separate middlewares. Middlewares always take the arguments req, res, and next (a function that says to go to the next middleware in the list).
So, you might write:
authorController.findAuthorsByFirstAndLastName = function(req, res, next) { if (!(req.query.firstName || req.query.lastName)) { res.locals.getFullAuthorList = true return next() } else { const query = /* whatever */ Author.find(query, (err, authors) => { if (err) return next(err) res.locals.authors = authors next() }) } } authorController.author_list = function(req, res, next) { if (!res.locals.getFullAuthorList) return next() // if we already have authors we don't need to do anything Author.find({}, (err, authors) => { if (err) return next(err) res.locals.authors = authors next() }) }Then in your route, you'd say:
router.get('/', authorController.findAuthorsByFirstAndLastName, authorController.author_list, (req, res) => { res.json({ authors: res.locals.authors }) })If you haven't seen res.locals before, it's just a property on the response object that is available for you to attach things to. It persists throughout the request/response cycle and is cleared for each new request.
更多推荐
发布评论