Circle CI通过SFTP部署Nuxt项目失败问题求助
Nuxt项目Circle CI部署SFTP上传失败问题修复建议
问题背景
此前数月使用Circle CI部署Nuxt项目到服务器均正常,两天前Circle CI出现故障后,SFTP上传环节开始失败。部署脚本与错误日志如下:
部署脚本
require('dotenv').config(); console.log("Starting upload") var SftpUpload = require('sftp-upload'), fs = require('fs'); var options = { host: process.env.FTP_HOST, username: process.env.FTP_UN, password: process.env.FTP_PW, path: './dist', remoteDir: process.env.FTP_PATH, dryRun: false, } console.log(options); sftp = new SftpUpload(options); console.log("sftp working ahead") sftp.on('error', function(err) { console.log(options) console.log("igoring error for now") //throw err; }) .on('uploading', function(progress) { console.log(options); console.log('Uploading', progress.file); console.log(progress.percent+'% completed'); }) .on('completed', function() { console.log('Upload Completed'); }) .upload();
错误日志
Starting upload { host: '************************', username: '*********', password: '************', path: './dist', remoteDir: '*****************************************', dryRun: false } sftp working ahead buffer.js:330 throw new ERR_INVALID_ARG_TYPE( ^ TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined at Function.from (buffer.js:330:9) at new Buffer (buffer.js:286:17) at onNEWKEYS (/home/circleci/repo/node_modules/ssh2/lib/Connection.js:2282:29) at Parser.<anonymous> (/home/circleci/repo/node_modules/ssh2/lib/Connection.js:123:5) at Parser.emit (events.js:314:20) at Parser.parsePacket (/home/circleci/repo/node_modules/ssh2/lib/Parser.js:468:12) at Parser.execute (/home/circleci/repo/node_modules/ssh2/lib/Parser.js:249:14) at Socket.<anonymous> (/home/circleci/repo/node_modules/ssh2/lib/Connection.js:523:18) at Socket.emit (events.js:314:20) at addChunk (_stream_readable.js:297:12) { code: 'ERR_INVALID_ARG_TYPE' } npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! nyb.nyb.nyb@1.0.0 deploy: `node deploy-sftp.js` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the nyb.nyb.nyb@1.0.0 deploy script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! /home/circleci/.npm/_logs/2022-09-16T08_55_31_507Z-debug.log Exited with code exit status 1 CircleCI received exit code 1
问题分析
错误源于sftp-upload依赖的ssh2库在处理密钥交换(onNEWKEYS阶段)时,传入了undefined参数到Buffer构造函数,核心原因是库版本与Node.js版本不兼容:
- Circle CI环境默认Node.js版本更新,旧版
ssh2无法适配新版Node的Buffer API - 依赖安装时拉取了
ssh2的更新版本,与停止维护的sftp-upload存在兼容性冲突
修复方案
方案1:锁定ssh2兼容版本
若需继续使用sftp-upload,可通过npm resolutions锁定兼容版本(需npm 7+支持):
- 在
package.json中添加配置:
"resolutions": { "ssh2": "^0.8.9" }
- 修改Circle CI依赖安装步骤为
npm ci,确保依赖版本严格匹配package-lock.json - 重新运行部署流水线
方案2:替换为维护活跃的SFTP库
sftp-upload已多年未更新,建议替换为ssh2-sftp-client,示例代码如下:
require('dotenv').config(); const Client = require('ssh2-sftp-client'); const fs = require('fs'); const path = require('path'); const sftp = new Client(); const config = { host: process.env.FTP_HOST, username: process.env.FTP_UN, password: process.env.FTP_PW }; // 递归上传目录 async function uploadDir(localDir, remoteDir) { const items = fs.readdirSync(localDir, { withFileTypes: true }); // 确保远程目录存在 try { await sftp.stat(remoteDir); } catch { await sftp.mkdir(remoteDir, true); } for (const item of items) { const localPath = path.join(localDir, item.name); const remotePath = path.join(remoteDir, item.name); if (item.isDirectory()) { await uploadDir(localPath, remotePath); } else { await sftp.put(localPath, remotePath); console.log(`已上传: ${localPath} -> ${remotePath}`); } } } // 执行上传 sftp.connect(config) .then(() => uploadDir('./dist', process.env.FTP_PATH)) .then(() => console.log('上传完成')) .catch(err => { console.error('上传失败:', err.message); process.exit(1); }) .finally(() => sftp.end());
使用步骤:
- 安装新依赖:
npm install ssh2-sftp-client --save-dev - 替换原部署脚本为上述代码
- 重新运行部署流水线
方案3:固定Circle CI的Node.js版本
检查Circle CI配置文件(.circleci/config.yml),指定之前正常运行的Node.js版本,示例:
jobs: build: docker: - image: circleci/node:14.18.0 # 替换为之前正常使用的Node版本 steps: - checkout - run: npm install - run: npm run generate - run: npm run deploy
内容的提问来源于stack exchange,提问作者Efraim Dahl
相关产品推荐
相关产品推荐

