Node.js Lambda中Axios上传文件至Dailymotion仅传首段停滞问题排查
问题:Node.js Lambda函数上传文件至Dailymotion仅上传首段后停滞
我尝试通过Node.js Lambda函数将文件上传至Dailymotion,使用了如下代码:
// Download the original file to the `tmp` folder of Lambda. await axios.get('https://cdn.mysite.com/source.mp4', { responseType: 'stream' }) .then( response => { response.data.pipe(fs.createWriteStream('/tmp/video.mp4')); }) .catch(error => { console.log(error); }); const form = new FormData(); form.append('file', fs.createReadStream('/tmp/video.mp4')); // Post the file to Dailymotion API. axios.post('https://upload-xx.xxx.dailymotion.com/upload?uuid=xxxxx&seal=xxxxx&extra=xxxxx', form, { headers: { ...form.getHeaders, 'Content-Type': 'multipart/formdata', 'Content-Length': fs.statSync('/tmp/video.mp4').size }, }) .then(response => { console.log(response); }) .catch(error => { console.log(error); });
我可通过URL https://upload-xx.xxx.dailymotion.com/progress?uuid=xxxxx 查看上传进度,但发现仅上传文件首段后便停滞,且未收到任何报错或响应。请问我遗漏了什么?
问题排查与修复方案
1. 文件下载未等待写入完成就启动上传
你用await等待了axios.get请求完成,但response.data.pipe(fs.createWriteStream('/tmp/video.mp4'))是异步写入操作,await并不会等待文件写入完成就执行后续的上传代码。此时读取/tmp/video.mp4时,文件可能只写入了一部分,导致上传到Dailymotion的内容不完整,上传停滞。
修复方式:将文件写入操作包装成Promise,等待写入完成后再执行上传:
// 替换原下载代码 await new Promise((resolve, reject) => { axios.get('https://cdn.mysite.com/source.mp4', { responseType: 'stream' }) .then(response => { const writeStream = fs.createWriteStream('/tmp/video.mp4'); response.data.pipe(writeStream); writeStream.on('finish', resolve); writeStream.on('error', reject); }) .catch(reject); });
2. FormData头部配置错误
form.getHeaders是一个方法,需要调用form.getHeaders()才能获取正确的头部对象,原代码中没有调用方法,导致头部信息错误。- 手动设置
Content-Type: 'multipart/formdata'会覆盖FormData自动生成的正确头部(FormData的头部会包含boundary参数,这是multipart/form-data请求必需的),导致服务端无法正确解析请求体。 - 手动设置
Content-Length没有必要,且如果文件还未写完就获取文件大小,会导致长度不准确,FormData和axios会自动处理Content-Length。
修复方式:移除手动设置的Content-Type和Content-Length,正确调用getHeaders()方法:
// 替换原上传的headers配置 headers: { ...form.getHeaders(), // 移除手动设置的Content-Type和Content-Length }
3. Lambda临时目录的注意事项
Lambda的/tmp目录有空间限制(默认512MB),如果你的视频文件超过这个大小,会导致写入失败,进而上传不完整。可以检查文件大小是否超出限制。
修复后的完整代码示例
const axios = require('axios'); const fs = require('fs'); const FormData = require('form-data'); exports.handler = async (event) => { // 1. 下载文件到Lambda临时目录,等待写入完成 await new Promise((resolve, reject) => { axios.get('https://cdn.mysite.com/source.mp4', { responseType: 'stream' }) .then(response => { const writeStream = fs.createWriteStream('/tmp/video.mp4'); response.data.pipe(writeStream); writeStream.on('finish', () => { console.log('文件下载并写入完成'); resolve(); }); writeStream.on('error', (err) => { console.error('文件写入失败:', err); reject(err); }); }) .catch(err => { console.error('文件下载失败:', err); reject(err); }); }); // 2. 构建FormData const form = new FormData(); form.append('file', fs.createReadStream('/tmp/video.mp4')); // 3. 上传到Dailymotion API try { const response = await axios.post( 'https://upload-xx.xxx.dailymotion.com/upload?uuid=xxxxx&seal=xxxxx&extra=xxxxx', form, { headers: { ...form.getHeaders(), // 可添加其他必要的头部,比如Authorization(如果需要) }, // 可选:添加超时配置,避免无响应停滞 timeout: 300000 // 5分钟超时 } ); console.log('上传成功:', response.data); return { statusCode: 200, body: JSON.stringify('上传成功') }; } catch (error) { console.error('上传失败:', error.response?.data || error.message); return { statusCode: 500, body: JSON.stringify('上传失败') }; } };
内容的提问来源于stack exchange,提问作者Jaafar Abazid
相关产品推荐
相关产品推荐

