У меня есть серверная часть NodeJS, которая прослушивает запрос POST с пакетом json. Используя информацию из пакета json, он создает файл csv примерно из 15 000 строк, а затем использует res.download для отправки файла csv обратно клиенту.
Чтение из облачной базы данных в файл csv не проблема. Я проверил файл на сервере, все строки там, и они точны. Однако в файле, который загружается на стороне клиента, может быть обрезано несколько сотен строк. Похоже, что res.download () запускается слишком рано, хотя я явно установил, что поток завершается после завершения цикла for или он запускается, когда он должен, но файл csv все еще буферизуется или что-то в этом роде
Вот мой код:
Сторона сервера:
app.post('/dashboard/download_data', function (req, res) {
let payload = req.body;
ref.orderByKey().once("value", function (snapshot) {
let data = snapshot.val();
writer.pipe(fs.createWriteStream('C:\\user\\EVCS_portal\\out.csv'));
for (let key in data) {
if (data.hasOwnProperty(key)) {
test_time = data[key]['time'];
writer.write({
time: data[key]['time'],
ac2p: data[key]['ac2p'],
dcp: data[key]['dctp']
})
}
}
writer.end('This is the end of writing\n');
writer.on('finish', () => {
console.info(test_time);
res.download('C:\\user\\EVCS_portal\\out.csv');
console.info('file sent out!')
});
})
Клиентская сторона js:
firebase.auth().currentUser.getIdToken(true).then(function (idToken) {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
let a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response);
a.download = download_date + '.csv';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
};
let url = "/dashboard/download_data";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.responseType = 'blob';
// Package our payload including the idToken and the date
let data = JSON.stringify({"idToken": idToken, 'date': download_date});
xhr.send(data);



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Код сервера кажется нормальным, но для кода клиента кажется, что загрузка слишком спешит.
Пожалуйста, посмотрите этот нить и попробуйте xhr.onload вместо xhr.onreadystatechange.
Еще одна вещь, которая, как я полагаю, может вызвать проблему с volumn, - это createObjectURL, пожалуйста, посмотрите: stackoverflow.com/questions/28307789/…
Вы не слушаете правильный поток для события 'finish', что приводит к отправке ответа до того, как csv закончит запись. Вы вызываете res.download(), когда writer завершил конвейерную передачу данных в поток, но не тогда, когда csv WriteableStream через fs.createReadStream() завершил запись всех передаваемых данных в своем потоке в файловую систему.
Вместо того, чтобы создавать WriteableStream для csv в pipe(), сохраните его в переменной и добавьте прослушиватель для события 'finish'. Прослушивание 'finish' на writer привело к тому, что ваш сервер ответил до того, как csv был готов.
app.post('/dashboard/download_data', function (req, res) {
let payload = req.body;
ref.orderByKey().once("value", function (snapshot) {
let data = snapshot.val();
let csvWriter = fs.createWriteStream('C:\\user\\EVCS_portal\\out.csv')
writer.pipe(csvWriter);
for (let key in data) {
if (data.hasOwnProperty(key)) {
test_time = data[key]['time'];
writer.write({
time: data[key]['time'],
ac2p: data[key]['ac2p'],
dcp: data[key]['dctp']
})
}
}
writer.end('This is the end of writing\n');
csvWriter.on('finish', () => {
console.info(test_time);
res.download('C:\\user\\EVCS_portal\\out.csv');
console.info('file sent out!')
});
})
})
В этом есть смысл, теперь код работает отлично. Большое спасибо
Спасибо за ваш ответ! Я пробовал это. Я просто заменил onreadystatechange на onload, и поведение не изменилось. Есть другие идеи?