vscode只是编辑器,不执行node.js文件上传逻辑;真正流式上传需由用户编写的node脚本完成,且必须在node运行时中执行。

VSCode 本身不执行 Node.js 文件上传逻辑,它只是编辑器;真正“通过 Node 环境发送文件流”的动作,必须由你写的 Node 脚本完成,且该脚本需在本地或远程 Node 运行时中执行。VSCode 只负责编写、调试、运行这个脚本。
如果你误以为 VSCode 内置了“Node 流式上传”功能,那容易卡在配置无效、命令不生效、甚至把 sftp.json 和 axios 混用——这是最常踩的坑。
Node 脚本发文件流 ≠ VSCode 的 SFTP 插件
VSCode 的 SFTP 插件走的是 SSH 协议(底层是 scp 或 sftp),它不经过 Node.js 运行时,也不支持自定义流处理(比如压缩、加签、分块、进度监听)。而你用 fs.createReadStream() + axios 或 node-fetch 发起的请求,是纯 HTTP(S) 行为,依赖目标服务器有对应接口(如 /upload)接收 multipart/form-data。
两者协议、路径、权限模型完全不同:
-
SFTP:需要服务器开 SSH 端口(默认 22),用户有系统级文件写入权限,路径是绝对文件系统路径 -
HTTP 上传:目标服务必须运行 Web 服务(如 Express),暴露上传接口,权限由该服务控制(比如只允许特定 token 上传到/appData/sqlFile/)
别指望在 sftp.json 里填个 host 就能让 fs.createReadStream 自动跑过去——它根本不会读那个配置。
用 axios 发 multipart 流必须手动设 content-length
Node 的 axios(v1.0+)默认不自动计算 FormData 的 content-length,而很多后端(尤其是 Express + multer 或老版 multiparty)会因 header 缺失直接拒收,返回 400 Bad Request 或静默失败。
正确做法是调用 formData.getLength(),等长度算出来再发请求:
const fs = require('fs');
const axios = require('axios');
const FormData = require('form-data');
<p>const form = new FormData();
form.append('sqlfiles', fs.createReadStream('/path/to/file.sql'));</p><p>form.getLength((err, length) => {
if (err) throw err;
axios.post('<a href="https://www.php.cn/link/d6d3803fc1ff073c8e9a3ae276b2d30d">https://www.php.cn/link/d6d3803fc1ff073c8e9a3ae276b2d30d</a>', form, {
headers: {
...form.getHeaders(),
'content-length': length // ⚠️ 必须显式设置
}
})
.then(res => console.log('OK:', res.status))
.catch(e => console.error('Fail:', e.response?.statusText));
});</p>
注意点:
- 别用
await form.getLength()—— 它不是 Promise,是回调函数 -
form.getHeaders()返回的 headers 不含content-length,必须手动补 - 如果目标服务用
multer,确保其limits.fileSize足够大,否则上传中途 500
本地调试时,路径和权限最容易出错
你在 VSCode 里写好脚本,按 F5 或 node script.js 运行,但以下问题几乎必现:
-
fs.createReadStream('f:/beijian.sql'):Windows 绝对路径在 Linux 服务器上当然打不开;本地脚本只能读本地磁盘,不能跨系统访问远端路径 - 权限被拒:Node 进程没权限读取该文件(尤其在 macOS / Linux 上,文件可能属 root 或其他用户)
- 路径拼错:比如
./mysqlout.bat实际在scripts/下,但脚本 cwd 是项目根目录,exec就找不到 - 中文路径或空格:Windows 下
child_process.exec对含空格路径极敏感,要用spawn+ 数组参数才稳
建议统一用 path.resolve(__dirname, '../data/beijian.sql'),并加存在性校验:
const filePath = path.resolve(__dirname, '../data/beijian.sql');
if (!fs.existsSync(filePath)) {
throw new Error(`File not found: ${filePath}`);
}
远端服务接收端必须匹配流式解析方式
你用 fs.createReadStream 发,远端就得用能消费流的中间件,比如 multer(推荐)或 busboy。老代码里用的 MULTIPARTY 虽然能用,但已归档,不维护,且 form.parse() 是异步回调风格,容易漏错误处理。
Express 示例(multer):
const multer = require('multer');
const upload = multer({ dest: './uploads/' });
<p>app.post('/upload', upload.single('sqlfiles'), (req, res) => {
if (!req.file) return res.status(400).send('No file uploaded');
// req.file.path 是临时路径,需用 fs.rename 移走
fs.rename(req.file.path, './appData/sqlFile/new.sql', () => {
res.send('OK');
});
});</p>
关键点:
-
upload.single('sqlfiles')中的字段名必须和前端form.append('sqlfiles', ...)一致 -
dest目录必须存在且 Node 进程有写权限,否则multer报ENOTDIR - 别忽略
req.file为空的情况——前端字段名错、文件为空、或 size 超限都会导致它不存在
真正的难点不在怎么写,而在两端字段名、路径、权限、header 长度、服务中间件选型这五处对齐。漏一个,就卡在“没反应”或“400”。











