错误:发送标头后无法设置标头。刷新获取请求后收到错误

时间:2018-07-04 17:51:54

标签: node.js express mqtt

以下代码在第一次执行时按预期工作。第二次通过失败,并显示以下错误:
Error: Can't set headers after they are sent.
基本上,我正在尝试从一系列已发布的mqtt主题中返回一条消息。我尝试了几种方法来执行此操作,但是对此行为感到茫然。以下代码显示了this MDN文章中详细介绍的使用诺言的尝试。我还尝试使用async / await(如果需要,我也可以发布此代码)。

概念
一个获取请求从网页到达,这触发了一个mqtt消息被发布到本地代理。一个单独的端点正在侦听此主题。在这种情况下,具有连接的网络摄像头的树莓派。接收到主题的信息是rpi的事,并以数据的形式发布带有url的返回消息。最初的mqtt发布者正在侦听此响应,并在响应中触发res.json()。
这是第一次工作,当我刷新网页时,它在发送后无法发送标头失败。一次重置如何处理?看来是这种情况。

punchitRoute.js

const express = require('express');
const punchitRoute = express.Router();
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://192.168.88.54:1883');

client.subscribe('returned', function(){
    console.log('subscribed');
})

async function img(){
    return new Promise(resolve =>{ client.on('message', function(topic, url){
            const message = {
                url: url.toString(),
                name: "garfield",
                date: Date.now()
            }
        return message;
        })
     })

}

 punchitRoute.get('/', async function(req, res){
    const mess = await img();
    console.log(mess);
    res.json(mess);
});

module.exports = punchitRoute;

server.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const punchit = require('./routes/punchitRoute');


app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended:false })); 

app.get("/", (req, res) => {

    res.json({
      name: "Express application",
      message: "welcome to punchit"
    })
  });

app.use('/api/punchit', punchit);

  const PORT = process.env.PORT || 6040;
  app.listen(PORT);
  console.log('server started on: ', PORT);

我的猜测是,我缺少使用快递的要求的生活中的基本事实。
预先感谢您的指导。

1 个答案:

答案 0 :(得分:0)

感谢jfriend00向我指出正确的方向。首先,发布的代码完全不正确。我对此感到非常困惑,随后重命名了文件punitRoute文件以继续使用其他方法进行处理,但是却忘记了在server.js中重命名所需的文件!那是一个愚蠢的错误。

关于client.on('message', ...)的事件处理程序的第二条评论为我提供了查看事件循环所需的提示。

这里的想法是使用get请求中的mqtt从网络摄像头捕捉图像。获取请求进入快递服务器,触发对名为' returned' 的主题的订阅,并发布至名为' sunrise'的主题strong> ,并显示消息 “点击”

本地网络上有一个单独的终结点,并且正在侦听正在监听 '日出' 主题的本地mqtt代理(均与快递服务器共享) 。将映像保存到S3存储桶后,此端点广播 '返回' ,并将映像的URL作为消息发送回运行get请求的服务器。 mqtt函数运行良好,我遇到的问题是响应事件并未在响应结束时终止。为此,必须更改几件事。

  1. 将res.send发送到client.on 之后调用的函数中(这不能完全起作用,它允许发送,但仍返回错误)
  2. 添加了事件发射器,以一次又一次地查看触发了哪个事件(这使我对正在发生的事情有了一定的了解,但仍然没有消除错误)
  3. 研究了其他mqtt库(最终与async-mqtt呆在一起)
  4. 在res.send函数之后添加了client.unsubscribe两个主题(这无效)
  5. 最终找到了this的答案,这使我意识到我可以一直打电话给client.once!

这是获取请求的代码:

punchitRoute.get('/', async function(req, res){
//adding event listner 'send'
mqEvent.on('send', function(){
    console.log('added send');
});

let sendit = function(url){
    'send', //emmitting 'send'
    res.status(200).send(
        '<img src='+url.toString()+' />'+
        '<h1>PUNCHED!</h1>'+
        '<p>'+
        'name: garfield <br/> time: '+moment(Date.now()).tz("America/Louisville").format('MM-DD-YYYY'));
    }

client.subscribe('returned', function(){
    console.log('subscribed');
});
client.publish('sunrise', 'click');
//changed this to .once and no more errors
await client.once('message', async function callout(topic, url){
    try {

            mqEvent.on('message', function(){
                console.log('added message');
            });

        sendit(url.toString());

            // console.log(res);
        client.unsubscribe('returned', ()=>{
            console.log('unsubscribed');
        });
        client.unsubscribe('sunrise', ()=>{
            console.log('unsubscribed publish');
        });
        //clearing out the send event listeners
        mqEvent.removeAllListeners('send');
        console.log(mqEvent.listenerCount('send'));
        //clearing out the message event listeners
        mqEvent.removeAllListeners('message');

     } catch(e){
            console.log(e);
            console.log('error');
        }
    })
});

希望这可以使其他人也遇到类似的问题。