博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Node.js 解决Gzip下获取真实的下载进度问题
阅读量:6895 次
发布时间:2019-06-27

本文共 2430 字,大约阅读时间需要 8 分钟。

当在项目中需要获取接口response返回数据进度的时候通常是通过以下方式操作的

// AJAX        var xhr = newXMLHttpRequest();    xhr.open('GET','your-http-path');    xhr.onprogress = function(event){        if(event.lengthComputable){            // 获取返回报文总字节长度            let total = max=event.total;            // 当前已返回字节长度            let loaded =event.loaded;            // 计算下载进度            return 100 * (loaded / total);        }    };        // Axios    axios.create({        withCredentials: true,        headers:{            'X-Requested-With': 'XMLHttpRequest'        },        onDownloadProgress: p => {             return 100 * ( p.loaded / p.total )         }})复制代码

实际上total的数值是从response headers的Content-Length获取的,但是当后端服务或者nginx开启gzip之后,Content-Length的长度是gzip压缩之后的,然而loaded得到的又是解压完实际的字符串长度,所以 total 和 loaded并不能等效相除等到正确的百分比。

google了很多 solution 并不能很好解决以上的问题,忽然灵机一动想到以下的solution


我使用的是Axios作为前端http请求库ajax 监听Progress事件句柄,回调参数中对象event能获得请求返回头,但是这个headers中只携带了Content-type 和 Content-Length, 我尝试着将未压缩的数据的大小通过设置Content-type的值携带过去Content-Type: application/json;charset=utf-8;real-length=2018结果成功的得到了以下的方案补充1:有人会问为什么不自定义一个headers,通过自定义的头进行传递,很遗憾我试过在服务端设置自定义headers头,但是就像上面所说的可能是从安全角度出发在progress事件中只能拿到Content-type 和 Content-Length。补充2: 有人又会说为什么不直接在服务端response headers中直接修改Content-Length的大小,要绕怎么大一圈把前后端都惊动了呢,因为就算你设置Content-length为未压缩之前的大小,前端发起请求时,需要Content-length 和 请求实际返回的二进制流的数据包大小是一样的,不然请求会假死。补充3: 在计算机编码中一个字节占用8 bit(1 byte = 8 bit),而一个字符可能是一个单字节字符,也可能是双字节字符。另外,Buffer.byteLength()方法在写http响应头时经常要用到,如果想改写http响应头Cotent-Length时,千万记得一定要用Buffer.byteLength()方法,而不要使用String.prototype.length属性复制代码

Front End Client

  • /util/axios.js
function getDownloadProgress(event){    	let header = e.currentTarget.getResponseHeader('Content-Type'),    	arr = header.split(';'),    	realLenghtArr = arr[2] && arr[2].split('=') || [],    	realLenght = realLenghtArr[1] || 0,    	progress = ( + e.loaded ) / (+ realLenght) * 100;    	return progress    }    axios.create({        withCredentials: true,        headers:{            'X-Requested-With': 'XMLHttpRequest'        },        onDownloadProgress: e => {            let progress = getDownloadProgress(e);           return progress;        }    })复制代码

Node.js Servers

  • /middleware/gzip.js
// 关键代码    let realLength = Buffer.byteLength(ctx.body, 'utf8');    ctx.set({        'Content-Type': `application/json;charset=utf-8;real-length=${ realLength }`    });    // gzip    let buf = await zlib.gzipSync(ctx.body);    ctx.body = buf;复制代码

转载地址:http://bjudl.baihongyu.com/

你可能感兴趣的文章
鱼油账号记录程序
查看>>
表单验证插件——validate
查看>>
【1500】Message Flood (SDUTOJ)
查看>>
Tomcat启动一闪而过
查看>>
递增的三元子序列
查看>>
预定义数组(超全局数组变量)
查看>>
吃了一惊!
查看>>
Tableau 字段及文件
查看>>
【FPGA】xilinx IOBUF的用法
查看>>
快捷键/光标
查看>>
AIX装机问题123
查看>>
gitconfig 配置文件[credential]使用记录
查看>>
CentOS Redhat Linux安装 Oracle Client 的注意点
查看>>
最短路
查看>>
vs2010 调试快捷键
查看>>
Java中的Timer和TimerTask来实现多线程
查看>>
小白学习appium之如何安装apk
查看>>
nginx启用status状态页
查看>>
谨防数组越界!
查看>>
Java异常处理
查看>>