Как справиться с загрузкой клиента gzip из серверного приложения Node.js? - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть вопрос об обработке ответа gzip на моем клиентском приложении. Я бы хотел, чтобы в браузере клиента всплыло предупреждение "как вы хотите справиться?" скачать приглашение.

Мой сервер Node.js сжимает мои файлы в формат gzip, а затем отправляет его с ответом на запись HTTP. Мой клиент получает статус HTTP 200, хотя размер ответа очень мал по сравнению с моим файлом, и ничто не заполняет мое веб-приложение. Я ожидал, что браузер обработает такой ответ на сервер, отправляющий gzip. похоже на то, как Gmail обрабатывает загрузку файлов. Можете ли вы помочь мне узнать, пропустил ли я что-нибудь?

server.js

var server = http.createServer(function(request, response) {
    if (request.url === '/download'){
        let data_zip = retrievedata()
        const scopedata_zip = ('./scopedata.txt.gz')
        response.writeHead(200, { 'Content-Encoding': 'gzip' });
        response.writeHead(200, { 'Content-Type': 'application/javascript' });
        response.write(scopedata_zip);
    }
})           

var retrievedata = () =>{
    const gzip = zlib.createGzip();
    const inp = fs.createReadStream('scopedata.txt');
    const out = fs.createWriteStream('scopedata.txt.gz');
    inp.pipe(gzip).pipe(out);
    return out
}

Client.js

var downloadData=()=>{
var xhr = new XMLHttpRequest();
xhr.open('POST', 'download', true);
//xhr.setRequestHeader("Accept-Encoding", "gzip")
xhr.setRequestHeader("Encoding", "null")
xhr.onload = function (){
    if(this.status == 200){
        let form = document.createElement("form");
        let element1 = document.createElement("input"); 
        document.body.appendChild(form);
        let response = this.responseText
        console.log(response)
        document.getElementById("state").innerHTML = 'download'
        document.getElementById("index").innerHTML = response;
        // document.getElementById("state").appendChild(form)
    }
}

xhr.onerror = function(err){
    console.log("request error...",err)
}

xhr.send()

}

Клиент просто заполняет мой индекс div ответом, но ничего не получено.

мой файл gzip составляет 327 МБ. Сеть Chrome Inspector сообщает, что этот запрос составляет всего 170 Б, поэтому я не получаю файл.

Примечание xhr.setRequestHeader("Accept-Encoding", "gzip") закомментировано, потому что я получаю эту ошибку: Отказался устанавливать небезопасный заголовок "Accept-Encoding". Я установил его в null, чтобы браузер мог справиться с этим.

Любой вклад в то, что я делаю неправильно?

1 Ответ

0 голосов
/ 20 сентября 2018

Было три вещи, которые я делал неправильно.Мне удалось открыть окно браузера, создав новый элемент, проверив, имеет ли элемент атрибут загрузки и добавив XHR.Response в качестве местоположения из href.Вторая часть моей проблемы не получала почтовый файл с соответствующими заголовками запроса.Поскольку размер моего zip-файла был больше, браузер обрабатывает двоичный поток буфера как большой двоичный объект.Подробнее о типах ответов XHR XHR.response .Другая проблема была на моей стороне сервера, которая использовала fs.readFile, чтобы прочитать zip как буфер.Поскольку мой zip был составлен из нескольких файлов fs.readFile, он перестанет читать, как только достигнет конца первого файла.

, поэтому мой клиентский код выглядит так:

var xhr = new XMLHttpRequest();
document.getElementById("state").innerHTML = ' '
document.getElementById("index").innerHTML = ' ';
xhr.open('POST', 'download', true);
xhr.setRequestHeader('Content-disposition', 'attachment')
xhr.setRequestHeader("Content-type","application/zip"); //content-type must be set
xhr.setRequestHeader("Encoding", "null") //unsure of why I need this but it doesnt work with out it for me
xhr.responseType = "blob"; // This must be set otherwise the browser was interpretting the buffer stream as string instead of binary

xhr.onload = function (){
    if(this.status == 200){
        let form = document.createElement("form");
        let element1 = document.createElement("input"); 
        document.body.appendChild(form);

        let response = this.response // defined as blob above
        document.getElementById("state").innerHTML = 'download'
        document.getElementById("index").innerHTML = response;
        var blob = new Blob([response], {type: "application/zip"});
        var file = URL.createObjectURL(blob);
        filename = 'Data.zip'
        var a = document.createElement("a");
        if ("download" in a) { //check if element can download
          a.href = file;
          a.download = filename;
          document.body.appendChild(a);
          a.click(); //automatically browser download
          document.body.removeChild(a);
    }
}

На стороне сервера

else if (request.url === '/download'){
                    archiveZip((data)=>{ // using archivezip and adding a callback function to insert my routes XHR response
                        response.setHeader('Content-Type', 'application/zip')
                        response.setHeader('Content-Length', data.length) // this is important header because without it the browser might truncate the entire response especially if there are end of file characters zipped up in the buffer stream
                        response.setHeader('Content-disposition', 'attachment; filename="Data.zip"');
                        response.end(data);
                    })

                }


var archiveZip = (callback) =>{
var output = fs.createWriteStream(__dirname + '/Data.zip'); //output
var archive = archiver('zip', {zlib: { level: 9 }});

output.on('close', function() {
  console.log(archive.pointer() + ' total bytes');
  console.log('archiver has been finalized and the output file descriptor has closed.');
  fs.readFile('./Data.zip', function (err, content) {
                        if (err) {
                            response.writeHead(400, {'Content-type':'text/html'})
                            console.log(err);
                            response.end("No such file");    
                        } else {
                            callback(content);
                        }
                    });
});

output.on('end', function() {
  console.log('Data has been drained');
});

archive.on('error', function(err) {
  throw err;
});

archive.pipe(output);

// append a file
archive.file(data_files + '/parsed_scope.json', { name: 'parsed_scope.json' });
archive.file(data_files + '/scopedata_index.json', { name: 'scopedata_index.json' });
archive.file(data_files + '/scopedata.txt', { name: 'scopedata.txt' });
archive.finalize();

Есть много библиотек zip, которые я просматривал, которые могут обрабатывать архивирование каталога с несколькимифайлы и пошли с архиватором .Я хотел бы использовать встроенный zlib, который поставляется с узлом, но поддерживает только отдельные небольшие файлы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...