【问题标题】:Express.js Routing error: Can't set headers after they are sentExpress.js 路由错误:发送后无法设置标头
【发布时间】:2016-05-01 05:26:00
【问题描述】:

我不确定为什么会收到此错误。这是一个基于 express.js 构建的简单 API,能够添加和删除帖子。当我触发删除路由器时发生错误。我读过这个错误通常发生在有两个回调时,但是,我似乎找不到任何双重回调。

    _http_outgoing.js:344
    throw new Error('Can\'t set headers after they are sent.');
    Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
    at ServerResponse.header (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:718:10)
at ServerResponse.send (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:163:12)
    at ServerResponse.json (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:249:15)
    at /Users/bounty/Projects/_learning/react-express/server/routes/posts.js:86:9
    at nextTickCallbackWith0Args (node.js:452:9)
    at process._tickCallback (node.js:381:13)

这是我的 posts.js 路由器:

module.exports = function(router) {

    var Post = require('../models/post.js');

    // middleware for the api requests
    router.use(function(req, res, next) {
        // do logging
        console.log('something is happening.');
        next(); // make sure we go to our next route and don't stop here
    });

    // test route to make sure everything is working (accessed at GET http://localhost:8080/api)

    router.get('/', function(req, res) {
        res.json({ message: 'hooray! welcome to our api!' });   
    });

    // all routes here

    // routes that end in /posts
    router.route('/posts')

        // create a Post (accessed at POST http://localhost:7777/api/posts)
        .post(function(req, res) {
            var post = new Post();
            post.postTitle = req.body.postTitle; // set the post name (comes from request) 

            // save post and check for errors
            post.save(function(err) {
                if (err)
                    res.send();

                res.json({ message: 'post created!' });
            });
        })

        // get all Posts (accessed at GET http://localhost:7777/api/posts)
        .get(function(req, res) {
            Post.find(function(err, posts) {
                if (err)
                    res.send();

                res.json(posts);
            });
        });

    // routes that end in /posts for specific id
    router.route('/posts/:post_id')

        // get the post with that id
        .get(function(req, res) {
            Post.findById(req.params.post_id, function(err, post) {
                if (err)
                    res.send(err);

                res.json(post);
            });
        })

        // update the post with that id
        .put(function(req, res) {
            Post.findById(req.params.post_id, function(err, post) {
                if (err)
                    res.send(err);

                post.postTitle = req.body.postTitle;

                // save the post
                post.save(function(err) {
                    if (err)
                        res.send(err);

                    res.json({ message: 'post updated!' });
                });
            });
        })

        // deletes the post with that id
        .delete(function(req, res) {
            Post.remove({
                _id: req.params.post_id
            }, function(err, post) {
                if (err) {
                    res.send(err);
                }
                res.json({ message: 'post deleted!' });
            });
        });
}

【问题讨论】:

  • post.save()post.find() 实际上是做什么的?这是你的数据库吗?
  • @jfriend00 是的,save() 将帖子放入数据库。 Find() 从数据库中获取帖子。数据库是 MongoDB。

标签: node.js express


【解决方案1】:

你需要添加'return',这样你就不会回复两次了。

// save post and check for errors
post.save(function(err) {
    if (err) {
        return res.send();
    }
    res.json({ message: 'post created!' });
});

【讨论】:

  • 谢谢!这个答案解决了部分问题。我已经为此苦苦挣扎了好几个小时。
  • 编写中间件时,注意多次调用next()
  • 总是这样吗? res 语句必须始终返回?
  • @softcode 我认为这是因为如果出现错误,将调用res.send(),然后调用res.json({ message: 'post created!' });return 用作断路器,请注意if 语句没有else
  • 你也可以使用 if/else 语句代替 if 语句
【解决方案2】:

该特定错误消息几乎总是由于处理异步响应中的计时错误导致您在响应已发送后尝试在响应上发送数据。

这通常发生在人们将快速路由中的异步响应视为同步响应并最终发送两次数据时。


我看到你会得到这个的一个地方是在你的任何错误路径中:

当你这样做时:

       // save post and check for errors
        post.save(function(err) {
            if (err)
                res.send();

            res.json({ message: 'post created!' });
        });

如果post.save() 产生错误,您将执行res.send(),然后您将执行res.json(...)。您的代码需要有 returnelse,因此当出现错误时,您不会同时执行两个代码路径。

【讨论】:

    【解决方案3】:

    因此,在 Express 中尝试发送两次 res.end 时会发生这种情况,res.sendres.json 都这样做。在您的if(err) 块中,您需要return res.send(),因为res.send 异步运行并且res.json 也被调用。我想知道您的delete 路线是否有错误?希望这会有所帮助。

    最好的!

    【讨论】:

      【解决方案4】:

      您在同一个请求中使用了两次res.send()res.json()

      这首先发送标头,然后是响应正文,然后再次发送标头。 req.next 通常不是函数,next 是作为中间件的第三个参数传递的。如果您想使用下一个中间件,请使用它。 (假设您使用的是 Express 框架)

      【讨论】:

        【解决方案5】:

        为了完整起见,我还要提到: 有时问题可能出在您可能通过调用使用的中间件中 app.use.

        在检查之前答案中提到的明显错误后:

        你应该删除所有的app.use语句,然后一一重新引入,找到有问题的模块。

        【讨论】:

          【解决方案6】:
              If you are using res.send() inside any loop, then you need to break it after the use of res.send(). So that it won't allow resetting of the res headers again and again. 
              for e.g : 
              for(){
          if(){
          res.send();
          break;
          }
          else(){
          res.send();
          break;
          }    
              }
          In my case this is the problem and I solved it like this.
              Hope it may help someone in future.
              Thanks
          

          【讨论】:

            猜你喜欢
            • 2015-08-10
            • 1970-01-01
            • 2015-09-08
            • 1970-01-01
            • 1970-01-01
            • 2020-04-30
            • 1970-01-01
            • 2014-02-13
            • 2018-06-08
            相关资源
            最近更新 更多