背景
记录一个JavaScript的全栈项目,包括服务端及前端页面。前后端分别采用了umijs和nestjs框架。在服务端,涉及到远端登入其他服务器的功能,同时在登入到其他服务器后,需要进行一些shell操作。
问题
关于js远端登入服务器的功能,一开始采用了ssh2这个库,简单实用。
具体代码如下
import { Client } from 'ssh2';
export function sshCommand(login: ILogin): Promise<any> {
const client = new Client();
return new Promise((resolve) => {
client.connect(login)
.on('ready', (...args) => {
// shell命令
client.exec('docker ps', (e, ch) => {
ch.once('data', (chunk) => {
// 命令获取的内容
resolve(chunk.toString());
})
})
})
.on('close', () => {
console.log('connection closed')
})
.on('error', (e) => {
console.log(`connection error:${e}`)
})
});
}
export interface ILogin {
host: string,
password: string,
username: string,
port: number
}
在实际使用中,会存在如下问题:
- 命令只能够单个执行
- ch.once回调函数执行的时机存在问题,当chunk很长时,每次返回的内容不全,且长度不一
- 无法实现命令交互,例如scp拷贝是时,无法模拟控制台输入passwd的行为
解决
尝试了很久没有解决,在不经意间找到了那根救命稻草,ssh2shell库,传送门www.npmjs.com/package/ssh…
代码如下
export function transmitFile(fileName: string, destIP: string, login: ILogin, password: string) {
return new Promise((resolve) => {
const obj = {
server: login, // 登入服务器
commands: [
fileName // 操作命令 eg:scp...
],
/**
* 命令执行过程
* @param command
* @param response 终端返回的内容
* @param sshObj
* @param stream
*/
onCommandProcessing: function (command, response, sshObj, stream) {
// 终端打印的内容
// 转化为小写,这里是个坑,不同的服务器可能返回值不一样
// 本人遇到过Password和password这两种
if (response.toLocaleLowerCase().indexOf('password')) {
// 检测到当前需要输入目的端的密码
// 回车不能少
stream.write(`${password}\n`);
}
}
};
const ssh = new ssh2shell(obj);
ssh.connect();
});
}
同时,上述1、2问题也能通过ssh2shell这个库来解决,唯一缺点就是找到的相关内容,都是英文的,阅读起来增加了一些困难。好在,npm安装后,可以参考test去使用。
后记
当前也只是解决了眼前的问题,不知道后面的维护过程中是否会产生新的问题,但是办法总比困难多。