【问题标题】:How do I pass data returned from a controller to Express' router?如何将控制器返回的数据传递到 Express 的路由器?
【发布时间】:2018-03-20 01:53:54
【问题描述】:

我正在尝试将数据返回到我的作者端点。如果传递给端点的 url 不包含查询参数,我希望路由器返回可用作者的完整列表。如果 url 包含 firstName 和 lastName 参数,我希望控制器找到匹配的作者,并将该数据传递回路由器。

目前,如果我发送网址 http://localhost:3001/authorshttp://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);
     });
  };

【问题讨论】:

    标签: javascript node.js express


    【解决方案1】:

    当您的路线中有两个 res.[whatever]s 时,您会得到 cannot set headers after they are sent。所以你有res.send(functionCallThatAlsoDoesRes.Send)。这就是导致错误的原因。

    如果您希望路由在请求和响应之间执行多个操作,您可以将它们编写为单独的中间件。中间件始终采用参数 reqresnext(表示转到列表中的下一个中间件的函数)。

    所以,你可以写:

    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,它只是响应对象上的一个属性,您可以将其附加到。它在整个请求/响应周期中持续存在,并为每个新请求清除。

    【讨论】:

    • JSilv - 谢谢!效果很好,感谢您提供的所有信息。
    • 你是我的救星!遇到了类似的问题,只是无法克服最后的障碍。谢谢你的解释:)
    猜你喜欢
    • 2019-07-26
    • 1970-01-01
    • 2020-10-18
    • 2017-12-04
    • 1970-01-01
    • 2012-04-03
    • 2023-04-04
    • 1970-01-01
    • 2017-11-27
    相关资源
    最近更新 更多