MongoDB更改流-错误[ERR_HTTP_HEADERS_SENT]

时间:2019-09-02 14:57:52

标签: node.js mongodb xmlhttprequest

我正在尝试构建一个应用程序,该应用程序现在仅可通过控制台在客户端浏览器中记录Mongo文档。我了解在服务器端可以很好地使用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)
        });
    });
};

但是,我正在努力在客户端复制相同的内容。到目前为止,我所做的是在客户端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();
});

并且我已将服务器端代码更改为如下形式:

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);
            });
        });
    };
});

从中获得的预期结果是每次我将新文档插入到集合中时,控制台都会使用新更改再次记录整个集合。但是,这适用于第一次插入,并且控制台会记录该集合,但是此后,我得到以下错误:

错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置

我知道这是因为我的服务器端代码现在具有

res.send(docs)

因此,我试图在第一次请求后每次再次发送标头。我的问题是我不知道如何将数据从服务器发送到客户端,以防止发生此错误。

有人可以引导我朝正确的方向前进吗?

1 个答案:

答案 0 :(得分:1)

对不起,评论的答案太长了。

这意味着您的回复已通过res.send(docs)发送,您可以修改该响应(它已发送)。

一些可能的解决方案是:

  • 使用网络套接字
  • /load-options上使用轮询间隔
  • 在输出中使用流将数据从mongo流发送到客户端。

最后一个未知的解决方案是:

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);

我的建议是每次修改数据时都避免使用mongo.connect