如何将从控制器返回的数据传递到Express'路由器? [英] How do I pass data returned from a controller to Express' router?
问题描述
我正在尝试进行各种各样的操作以将数据返回到Author端点.如果传递给端点的url不包含查询参数,则我希望路由器返回可用作者的完整列表.如果该URL包含firstName和lastName参数,则我希望控制器查找匹配的作者,然后将该数据传递回路由器.
当前,如果我发送网址 http://localhost:3001/authors
或 http://localhost:3001/authors?firstName = tom& lastName = dooly
,出现错误错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头
.
谁能告诉我为什么会这样以及如何解决?
主要:
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('错误',console.error.bind(控制台,'MongoDB连接错误:'));//查看引擎设置app.set('views',path.join(__ dirname,'views'));;app.set('view engine','jade');//将图标图标放置在/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);//捕获404并转发到错误处理程序app.use(function(req,res,next){var err = new Error('未找到');err.status = 404;next(err);});app.use(function(err,req,res,next){res.locals.message = err.message;res.locals.error = req.app.get('env')==='开发'吗?呃 : {};res.status(err.status || 500);res.render('错误');});module.exports =应用程序;
路线:
var express = require('express');var router = express.Router();var authorController = require('../controllers/authorController');authorController.findAuthorsByFirstAndLastName);router.get('/',函数(req,res){if(req.query.firstName || req.query.lastName){res.send(authorController.findAuthorsByFirstAndLastName(req,res));}别的{res.send(authorController.author_list(req,res));}});module.exports =路由器;
控制器:
var Author = require('../models/author')var async = require('async')Exports.author_list = function(req,res,next){Author.find({},function(err,authors){如果(错误){res.send(err);}return.json(作者);});};exports.findAuthorsByFirstAndLastName =函数(要求,要求,下一项){var query = {}if(req.query.firstName || req.query.lastName){查询= {$ or:[{firstName:{$ regex:req.query.firstName,$ options:'i'}}},{lastName:{$ regex:req.query.lastName,$ options:'i'}}]}}别的 {返回res.status(500).send({错误:'无法解析数据'});}var firstName = req.body.firstName;var lastName = req.body.lastName;Author.find(query,function(err,authors){if(err){res.send(err);}res.json(作者);});};
当您有两个 res时,您将得到
在你的路线上.因此,您有发送后无法设置标头
.[无论如何] res.send(functionCallThatAlsoDoesRes.Send)
.这就是导致错误的原因.
如果您希望路由在请求和响应之间采取多种措施,则可以将其编写为单独的中间件.中间件始终采用参数 req
, res
和 next
(该函数表示将转到列表中的下一个中间件).>
因此,您可能会写:
authorController.findAuthorsByFirstAndLastName = function(req,res,next){如果(!(req.query.firstName || req.query.lastName)){res.locals.getFullAuthorList = true返回next()} 别的 {const查询=/*不管*/Author.find(query,(err,authors)=> {如果(err)返回next(err)res.locals.authors =作者下一个()})}}authorController.author_list = function(req,res,next){如果(!res.locals.getFullAuthorList)返回next()//如果我们已经有作者,则无需执行任何操作Author.find({},(err,authors)=> {如果(err)返回next(err)res.locals.authors =作者下一个()})}
然后在您的路线中,您会说:
router.get('/',authorController.findAuthorsByFirstAndLastName,authorController.author_list,(req,res)=> {res.json({authors:res.locals.authors})})
如果您以前从未见过 res.locals
,则它只是响应对象上的一个属性,可用于附加内容.它会在请求/响应周期中持续存在,并为每个新请求清除.
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);
});
};
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.
这篇关于如何将从控制器返回的数据传递到Express'路由器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!