在企业客服及资料归档系统中,经常需要自动保存用户通过微信发送的高清图片、视频或各类办公文档。如果处理不当,极易导致主线程阻塞、内存溢出(OOM)或网络请求超时。本文将基于 Node.js 带来一套流式文件下载解决方案。
一、 技术难点分析
微信传输的文件通常需要通过带鉴权的 CDN 链接进行拉取。如果文件较大(如几十MB的视频),直接加载进内存会撑爆 Node.js 默认的内存限制。因此,必须使用stream模块进行管道流(Pipe)传输。
二、 核心代码实现
我们使用 TypeScript 编写核心下载逻辑,结合axios的流响应模式直接写入本地磁盘。
import axios from 'axios'; import * as fs from 'fs'; import * as path from 'path'; interface DownloadTask { fileUrl: string; savePath: string; } /** * 流式下载微信媒体文件 */ async function downloadMediaFile(task: DownloadTask): Promise<void> { const writer = fs.createWriteStream(task.savePath); // 请求下载地址,响应类型设为 stream const response = await axios({ url: task.fileUrl, method: 'GET', responseType: 'stream', headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' } }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); } // 模拟从接口获取到媒体下载地址后调用 async function handleImageMessage(mediaUrl: string) { const fileName = `media_${Date.now()}.jpg`; const targetPath = path.resolve(__dirname, 'downloads', fileName); try { await downloadMediaFile({ fileUrl: mediaUrl, savePath: targetPath }); console.log(`Successfully downloaded: ${targetPath}`); } catch (error) { console.error('Download failed:', error); } }三、 最佳实践总结
目录预创建:在写入文件前,必须通过
fs.mkdirSync(..., { recursive: true })确保目标文件夹存在,否则会触发ENOENT异常。并发控制:当接收到高并发图片推送时,切勿无限制同时发起下载,建议引入
p-limit等队列控制库,限制同时下载的文件数,保护本地磁盘 IO 与网络带宽。