如何使用Axios获取GET请求含请求头的完整大小
解决方案
首先明确:你无法通过修改客户端请求配置让服务端放弃分块传输、返回Content-Length头。Transfer-Encoding: chunked是服务端的传输策略,当响应体大小在响应发送前无法确定时,服务端就会采用分块编码,不会提前返回总长度,客户端没有权限修改这个服务端行为。
要统计包含请求头、请求体、响应头、响应体在内的完整流量大小,只能通过实际统计收发字节的方式实现,以下是Node.js环境下可直接运行的实现(浏览器端受Web API安全限制,无法拿到字节级精确的原始流量大小,只能获取解压后响应体的近似值)。
第一步:修正错误请求头
你当前代码里给GET请求加Content-Encoding: gzip是无效配置,这个头用于标记请求/响应体的编码格式,GET请求默认没有请求体,加这个头反而可能触发服务端异常,直接删掉即可。
第二步:字节级流量统计实现
通过axios拦截器+流处理,分别统计请求行、请求头、请求体、响应行、响应头、分块响应体的字节数,累加得到总大小:
const axios = require('axios'); const { PassThrough } = require('stream'); async function calcRequestTotalSize(url, customConfig = {}) { let totalBytes = 0; const reqInstance = axios.create({ ...customConfig, responseType: 'stream', // 设为false则统计gzip压缩后的实际传输字节,设为true统计解压后的业务字节 decompress: true }); // 统计请求侧字节 reqInstance.interceptors.request.use(config => { // 计算请求行长度 例:GET /api/v9/experiments HTTP/1.1\r\n const reqUrl = new URL(config.url, config.baseURL); const requestLine = `${config.method.toUpperCase()} ${reqUrl.pathname}${reqUrl.search} HTTP/1.1\r\n`; totalBytes += Buffer.byteLength(requestLine); // 计算请求头长度 Object.entries(config.headers).forEach(([key, val]) => { totalBytes += Buffer.byteLength(`${key}: ${val}\r\n`); }); totalBytes += Buffer.byteLength('\r\n'); // 头和体的分隔空行 // 计算请求体长度(GET请求无请求体时自动跳过) if (config.data) { const bodyContent = typeof config.data === 'string' ? config.data : JSON.stringify(config.data); totalBytes += Buffer.byteLength(bodyContent); } return config; }); const res = await reqInstance.get(url, { headers: { "Accept-Encoding": "gzip", "x-accept-encoding": "gzip" } }); // 统计响应侧头字节 const statusLine = `HTTP/${res.res.httpVersion} ${res.status} ${res.statusText}\r\n`; totalBytes += Buffer.byteLength(statusLine); Object.entries(res.res.headers).forEach(([key, val]) => { totalBytes += Buffer.byteLength(`${key}: ${val}\r\n`); }); totalBytes += Buffer.byteLength('\r\n'); // 逐块统计分块响应体字节 return new Promise((resolve, reject) => { const counter = new PassThrough(); res.data.pipe(counter); counter.on('data', chunk => totalBytes += chunk.length); counter.on('end', () => resolve(totalBytes)); counter.on('error', reject); }); } // 调用示例 calcRequestTotalSize("https://discord.com/api/v9/experiments").then(size => { console.log(`完整请求总大小(字节): ${size}`); })
注意事项
- 如果你要统计真实网络传输的流量消耗,把配置项
decompress设为false,此时统计的是gzip压缩后的实际传输字节,和网卡层面统计的流量值一致 - 分块传输的响应体不存在预计算的总长度,所有声称可以不接收完整响应就拿到大小的方法都是不可靠的
- 不要尝试手动给请求添加
Content-Length头修改传输编码,这个头是服务端生成响应时填写的,客户端强行设置不会改变服务端行为,反而会导致请求校验失败 - 浏览器端受同源策略和Web API限制,无法获取原始请求/响应头的精确字节长度,也无法区分压缩前后的流量差,只能拿到解压后响应体的长度,做不到精确的流量统计。
内容的提问来源于stack exchange,提问作者PhilZockt
相关产品推荐
相关产品推荐

