简体   繁体   English

MongoDB更改流-错误[ERR_HTTP_HEADERS_SENT]

[英]MongoDB Change Streams - Error [ERR_HTTP_HEADERS_SENT]

I'm trying to build an application which at the moment simply console logs Mongo documents in the client browser. 我正在尝试构建一个应用程序,该应用程序现在仅可通过控制台在客户端浏览器中记录Mongo文档。 I understand the Mongo change streams fine on the server side and have the following code to watch for inserts into the collection and when a change occurs, the dataset is reloaded: 我了解在服务器端可以很好地使用Mongo更改流,并具有以下代码来监视向集合中插入的内容,并在发生更改时重新加载数据集:

MongoClient.connect(MongoConnection.url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
    const db = client.db('test');
    const collection = db.collection('options');
    const changeStream = collection.watch();
    changeStream.on('change', next => {
        // If there is a change in the collection, reload the data.
        reload();
    });
});
function reload() {
    MongoClient.connect(MongoConnection.url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
        const db = client.db('test');
        const collection = db.collection('options');
        collection.find({}).toArray(function (err, docs) {
            client.close();
            console.log(docs)
        });
    });
};

However, I'm struggling to replicate the same on the client side. 但是,我正在努力在客户端复制相同的内容。 So far what I have done is created an XHR request in a client side js file which looks like this: 到目前为止,我所做的是在客户端js文件中创建了一个XHR请求,如下所示:

$(window).on('load', () => {
    function load_options() {
        var data = null;
        var xhr = new XMLHttpRequest();
        xhr.withCredentials = true;
        xhr.addEventListener("readystatechange", function () {
            if (this.readyState === 4) {
                if (this.responseText === "") {

                } else {
                    data = $.parseJSON(this.responseText);
                    $.each(data, function (i, item) {
                        console.log(item)
                    });
                }
            }
        });
        xhr.open("GET", "/dashboard/load-options");
        xhr.setRequestHeader("cache-control", "no-cache");
        xhr.send(data);
    };
    load_options();
});

And I have changed the server side code to look like this: 而且我将服务器端代码更改为如下所示:

router.get('/load-options', (req, res) => {
    MongoClient.connect(MongoConnection.url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
        const db = client.db('test');
        const collection = db.collection('options');
        const changeStream = collection.watch();
        changeStream.on('change', next => {
            // If there is a change in the collection, reload the data.
            reload();
        });
    });
    function reload() {
        MongoClient.connect(MongoConnection.url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
            const db = client.db('test');
            const collection = db.collection('options');
            collection.find({}).toArray(function (err, docs) {
                client.close();
                res.send(docs);
            });
        });
    };
});

The desired outcome from this is for every time I insert a new document into the collection, the console logs the entire collection again with the new changes. 这样的预期结果是每次我将新文档插入到集合中时,控制台都会使用新更改再次记录整个集合。 However, This works for the first insert and the console logs the collection, but after that I'm getting the following error: 但是,这适用于第一次插入,并且控制台记录了该集合,但是此后,我得到以下错误:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头

I know this is because my server side code now has 我知道这是因为我的服务器端代码现在有

res.send(docs)

So I'm trying to send the headers again every time after the first request. 所以我试图在第一次请求后每次再次发送标头。 My issue is that I don't know how I should be sending the data over from the server to the client to prevent this error. 我的问题是我不知道如何将数据从服务器发送到客户端,以防止发生此错误。

Can anyone guide me in the right direction? 谁能指导我正确的方向?

Sorry, too long answer for comments. 抱歉,回答的时间太长。

It means that your response has been sent with res.send(docs) once done, you canot modify the response (it has been sent). 这意味着您的响应已随res.send(docs)发送完成,您可以修改响应(已发送)。

Some possible solutions are : 一些可能的解决方案是:

  • use a websocket 使用网络套接字
  • use a polling interval on /load-options /load-options上使用轮询间隔
  • use a stream on the output to send data to the client from the mongo stream. 在输出上使用流将数据从mongo流发送到客户端。

The last solution which is non well known would be : 最后一个未知的解决方案是:

const out = new Readable();
const reload = () => {
        MongoClient.connect(MongoConnection.url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
            const db = client.db('test');
            const collection = db.collection('options');
            collection.find({}).toArray(function (err, docs) {
                client.close();
                out.push(docs);
            });
        });
    };
changeStream.on('change', next => {
  reload();
});
out._read = () => {};
res.type('application/json').send(out);

My advice would be also to avoid the mongo.connect each time a data is modified. 我的建议还应避免每次修改数据时使用mongo.connect

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM