You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 03:16:04