如何将从控制器返回的数据传递到Express'路由器? [英] How do I pass data returned from a controller to Express' router?

查看:22
本文介绍了如何将从控制器返回的数据传递到Express'路由器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试进行各种各样的操作以将数据返回到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆