求助:WhatsApp API音频下载失败,Node.js实现遇阻
修复WhatsApp API音频下载失败的问题
1. 清理冗余请求头
GET请求不需要设置Content-Type(该头用于POST请求上传内容时声明类型),Transfer-Encoding是服务器端响应的头,客户端手动设置会触发400错误;另外Host头Node.js的fetch会自动根据URL生成,手动设置可能出现不匹配(比如忽略URL中的端口)。建议移除这些冗余头,保留必要字段:
headers: { 'Authorization': `Bearer ${apiKey}`, 'User-Agent': 'PostmanRuntime/7.42.0', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', },
2. 处理响应压缩
如果请求中声明了Accept-Encoding,服务器会返回压缩后的内容,直接pipe到文件会导致音频损坏或下载失败。需要用zlib模块解压后再写入文件:
先引入zlib模块:
const zlib = require('zlib');
再修改响应流处理逻辑:
let stream = response.body; // 根据响应头判断压缩类型并解压 const contentEncoding = response.headers.get('content-encoding'); if (contentEncoding === 'gzip') { stream = stream.pipe(zlib.createGunzip()); } else if (contentEncoding === 'deflate') { stream = stream.pipe(zlib.createInflate()); } else if (contentEncoding === 'br') { stream = stream.pipe(zlib.createBrotliDecompress()); } stream.pipe(file);
3. 修正Promise逻辑
原代码的Promise没有覆盖所有错误场景,且file.close()属于冗余操作(流结束后WriteStream会自动关闭)。简化并完善错误处理:
return new Promise((resolve, reject) => { const handleError = (err) => { fs.unlink(filePath, () => {}); reject(err); }; stream.on('finish', () => { console.log(`Downloaded audio to ${filePath}`); resolve(); }); stream.on('error', handleError); file.on('error', handleError); });
完整修改后的代码
const fs = require('fs'); const path = require('path'); const zlib = require('zlib'); async function downloadAudio(url, outputPath, audioType) { const filePath = path.join(outputPath, `audio.${audioType}`); const file = fs.createWriteStream(filePath); try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${apiKey}`, 'User-Agent': 'PostmanRuntime/7.42.0', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', }, }); if (!response.ok) { throw new Error(`Failed to get '${url}' (${response.status})`); } let stream = response.body; const contentEncoding = response.headers.get('content-encoding'); if (contentEncoding === 'gzip') { stream = stream.pipe(zlib.createGunzip()); } else if (contentEncoding === 'deflate') { stream = stream.pipe(zlib.createInflate()); } else if (contentEncoding === 'br') { stream = stream.pipe(zlib.createBrotliDecompress()); } stream.pipe(file); return new Promise((resolve, reject) => { const handleError = (err) => { fs.unlink(filePath, () => {}); reject(err); }; stream.on('finish', () => { console.log(`Downloaded audio to ${filePath}`); resolve(); }); stream.on('error', handleError); file.on('error', handleError); }); } catch (error) { fs.unlink(filePath, () => {}); console.error(`Error downloading the audio: ${error.message} \n${error}`); throw error; // 抛出错误让调用方处理 } }
额外排查点
- 确认
apiKey有效,且音频URL未过期(WhatsApp媒体URL通常为短期有效,获取后需尽快下载) - 用Postman的「Code」功能生成Node.js fetch代码,对比自身代码的请求头和逻辑差异
- 检查Node.js版本,旧版本内置fetch可能存在兼容性问题,建议升级到v18+或使用最新版
node-fetch包
内容的提问来源于stack exchange,提问作者Nova09
相关产品推荐
相关产品推荐

