如何将控制器返回的数据传递给Express'路由器?(How do I pass data returned from a controller to Express' route

编程入门 行业动态 更新时间:2024-10-26 00:28:23
如何将控制器返回的数据传递给Express'路由器?(How do I pass data returned from a controller to Express' router?)

我试图让所有种类的数据返回到我的作者端点。 如果传递给端点的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.

更多推荐

本文发布于:2023-08-06 16:50:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1452884.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:路由器   如何将   控制器   Express   pass

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!