Node.js调用上传接口时请求为空,文件上传失败
问题:使用FormData+Axios上传本地文件,服务器接收为空
我尝试通过上传API把本地文件传到远程服务器,用Form Data附加文件,但服务器那边始终收到空文件,以下是我的代码:
let filename = 'NJ-09_13_22-nodup.csv' let noDupFile = config.OUTPUT_PATH + '/' + filename const noDupFileReadStream = fs.createReadStream(noDupFile) .on('data', function (chunk) { console.log('chunk', chunk) }).on('end', async function () { console.log('noDupFileReadStream end') const form = new FormData() form.append('file', noDupFileReadStream) const requestConfig = { headers: { ...form.getHeaders() }, httpAgent: new http.Agent({ keepAlive: true, maxSockets: Infinity }) } axios.post(`${config.XMINDER_URL}/utils/upload`, form, requestConfig).then(function (response) { console.log(response.data.url) }).catch(function (error) { console.log(error) }) })
问题根源
你犯了一个关键错误:在可读流的end事件触发后,才把流附加到FormData。
fs.createReadStream创建的是一次性可读流,当end事件触发时,流已经把所有数据读取完毕,内部指针走到末尾,此时再把这个流传给FormData,它已经没有任何数据可以被发送,服务器自然收到空文件。
另外,你监听data事件打印chunk的操作,会直接消耗流的数据(没有做暂停或重处理),进一步导致流提前耗尽。
修正方案
直接将未被消耗的可读流附加到FormData即可,不需要等到流读取结束。FormData会自动处理流的读取和上传过程,无需手动监听data或end事件。
同时建议给form.append加上文件名参数,确保服务器能正确识别文件名称(多数后端框架依赖这个参数解析文件)。
修正后的代码:
const filename = 'NJ-09_13_22-nodup.csv' const noDupFile = `${config.OUTPUT_PATH}/${filename}` const noDupFileReadStream = fs.createReadStream(noDupFile) // 直接创建FormData并附加流,无需等待end事件 const form = new FormData() // 第三个参数指定文件名,后端可正确获取文件名 form.append('file', noDupFileReadStream, filename) const requestConfig = { headers: { ...form.getHeaders() }, httpAgent: new http.Agent({ keepAlive: true, maxSockets: Infinity }) } axios.post(`${config.XMINDER_URL}/utils/upload`, form, requestConfig) .then(response => { console.log(response.data.url) }) .catch(error => { console.log(error) })
额外说明
- 如果需要验证文件是否存在,可在创建流前用
fs.existsSync或fs.promises.access做检查,避免因文件不存在导致上传失败 - 无需手动监听
data事件,除非你需要做加密、压缩这类额外数据流处理,否则会消耗流数据导致上传异常
内容的提问来源于stack exchange,提问作者Ahsan Hasan
相关产品推荐
相关产品推荐

