什么是webssh?
- webssh 泛指一种技术可以在网页上实现一个 SSH 终端
- ssh终端:用来通过ssh协议,连接服务器进行管理
- 运维开发方向:堡垒机登录、线上机器管理(因为运维人员不可能24小时携带电脑)
- 在线编程:提供一个编程环境
工作流程
安装依赖
npm i xterm
xterm是实现一个网页版的ssh的js库,目前更新到5.X的版本,由于项目比较老旧,安装的是3.X的版本,所以查看官网文档记得选对版本,xerm.js官网,如果是自己重新写,推荐用新的版本。值得注意的是:要学会看官网的文档,首页进去看到的文档教程比较少,更多详细的api和属性,放在了声明文件中: xterm.d.ts
引入
import { Terminal } from 'xterm';
import * as fit from 'xterm/lib/addons/fit/fit'; // 让终端适应父容器的插件
Terminal.applyAddon(fit); // 加载fit 插件
代码实现
html
<div id="cluster-terminal"></div>
js核心代码
// 点击一个连接按钮调用
connect() {
// 通过weosocket参数传递的参数
let params = {
cluster: this.cluster,
id: this.appId,
container: this.containerId,
host: this.rowInfo.node_ip,
port: 900,
cmd: this.select,
};
let config = this.$spaSdk.getPluginConfig(VUE_APP_PLUGIN_NAME);
const obj = spaSdk.config.PLUGIN_CONFIGS_MAP[VUE_APP_PLUGIN_NAME];
const wsurl = `${config['pod-websocket']}/v3/app/pod/terminal?${qs.stringify(params)}`;
// 初始化终端
this.initTerm(wsurl);
},
// 初始化终端
initTerm(url) {
this.websocket = new WebSocket(url);
this.connected = true;
this.websocket.onopen = evt => {
console.log('连接打开。。。');
// 创建一个终端实例 this.term
this.term = new Terminal({ scrollback: 2000 });
// 获取容器
let terminalContainer = document.getElementById('cluster-terminal');
while (terminalContainer.children.length) {
terminalContainer.removeChild(terminalContainer.children[0]);
}
// 在容器中打开终端
this.term.open(terminalContainer, true);
// 给中端设置样式 cursorBlink 配置光标是否闪烁
this.term.setOption('cursorBlink', true);
var initialGeometry = this.term.proposeGeometry();
// 获取终端的初始化的行和列,这个方法在文档中没有看到,通过查看其原型方法,确实存在
var cols = initialGeometry.cols;
var rows = initialGeometry.rows;
// 让终端适配父容器
this.term.fit();
// 初始化的时候将 终端的宽和高传递给后端(非常重要!非常重要!非常重要!),让后端终端的尺寸设置和前端的一致,否则会出,宽度没有占满或者输入很长命令的时候不会自动换行而是将同行的从前面进行覆盖
this.websocket.send('RESIZE_EXCE ' + rows + ' ' + cols);
// 监听终端的输入事件,将输入的消息通过websocket传递给后端
this.term.on('data', data => {
this.websocket.send(data);
});
// this.term.resize(cols, rows);
// 监听终端resize事件
this.term.on('resize', size => {
// 调整终端大小
this.term.resize(size.cols, size.rows);
// 将调整后的终端大小传递给后端,使后端的终端和前端的终端大小一致(非常重要!非常重要!非常重要!)
this.websocket.send('RESIZE_EXCE ' + size.rows + ' ' + size.cols);
});
// 监听window的resize 事件,使终端去使用父容器的大小,这时候就会触发终端的resize事件
window.onresize = () => {
this.term.fit();
};
// 监听websocket返回消息事件
this.websocket.onmessage = e => {
//将返回的消息写入终端
this.term.write(e.data);
if (e.data === 'CONN CLOSE') {
this.$Confirm.warning({
modalProps: {
confirmText: '确认',
showCancel: false,
},
content: `因为pod删除等原因,连接已关闭!`,
onOk() {},
});
}
};
this.websocket.onclose = evt => {
console.log('连接关闭额', evt);
this.connected = false;
};
};
},
值得注意的是:this.term.proposeGeometry(),在代码中看到了这句代码,因为不知道是什么意思,于是查看对应的文档,没有发现对应的api,难道是文档漏掉了?
最终效果
最大的坑
由于也是初次接触webssh和 xterm.js这个库,对于一些概念比较模糊不清,那么就很容易出现一些问题,让你丈二和尚,摸不着头脑,可能会出现前后端因为不懂相互踢皮球的问题;
-
初始化终端的时候,在终端输入很长的命令,命令没法输入到终端的最右边就会从当前行的签名开始输入,不会换行,解决办法:当websocket 连接后且终端也打开后,将终端的尺寸一定要传递给后端,这个时候如果后端说我不需要这个参数,那就是他不懂,让他去查资料。。。
-
当我们改变浏览器窗口大小的时候,终端中的内容不适应,不换行,消失等一些奇怪的问题,这都是因为后端的终端和前端不一致导致的,解决方法和上边同理。
参考文档
vue+xterm.js实现webssh踩坑之旅
xterm.js + vue + websocket实现终端功能(xterm 3.x+xterm 4.x)
Java实现WebSSH,自适应宽高、心跳检查、断开自动重连