我正在尝试构建一个应用程序,该应用程序现在仅可通过控制台在客户端浏览器中记录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)
因此,我试图在第一次请求后每次再次发送标头。我的问题是我不知道如何将数据从服务器发送到客户端,以防止发生此错误。
有人可以引导我朝正确的方向前进吗?
答案 0 :(得分:1)
对不起,评论的答案太长了。
这意味着您的回复已通过res.send(docs)
发送,您可以修改该响应(它已发送)。
一些可能的解决方案是:
/load-options
上使用轮询间隔最后一个未知的解决方案是:
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
。