xterm.js结合websocket实现web ssh
xterm.js的使用背景
实现一个web ssh来通过输入命令来控制k8s pod中的容器,支持/bin/bash
和/bin/sh
等
实现流程
前端只处理按键的发送,例如当想要输入ll命令来查看文件,当输入l的时候就通过ws连接向后端发送l的按键,再输入l就再发送l,输入回车就发送回车。监听键盘按下全部都通过xterm的onDate函数来监听。
前端终端的显示并不是前端控制的,而是通过后端返回的内容控制,例如当输入l的时候,前端并不使用xterm的write插入,而是通过ws将l发送给后端,后端通过ws返回l,前端监听ws的message来使用xterm的write插入。
xterm.js安装
npm i xterm
xterm.js初始化
采用vue2来实现xterm.js的初始化
import { Terminal } from 'xterm';
import Vue from 'vue';
class SelfTerminal extends Vue {
term = null;
mounted() {
// 初始化终端
this.initXterm();
}
initXterm() {
let term = new Terminal({
rendererType: 'canvas', // 渲染类型
convertEol: true, // 启用时,光标将设置为下一行的开头
disableStdin: false, // 是否应禁用输入
cursorBlink: true, // 光标闪烁
theme: {
foreground: '#ECECEC', // 字体
background: '#000000', // 背景色
cursor: 'help', // 设置光标
lineHeight: 20,
},
});
this.term = term;
// 发送消息
this.terminalSendMessage();
}
terminalSendMessage() {
const term = this.term;
// 发送消息 键入消息
term.onData((content) => {
this.handleSocketSendMessage(content);
});
}
}
xterm.js渲染
通过xterm实例上的open命令为DOM绑定渲染终端
<div class="terminalContainer">
<div ref="terminal" class="xterm" />
</div>
this.term.open(this.$refs.terminal);
xterm.js常见插件介绍
xterm-addon-webgl
xterm-addon-webgl
插件的作用是使用webGL来加速渲染,如果没使用该插件xterm生成的终端是通过DOM渲染的,如果使用该插件则通过canvas渲染。
xterm-addon-webgl
插件可以在xterm初始化的时候添加,将DOM渲染改为webGL来加速渲染。
const webglAddon = new WebglAddon();
term.loadAddon(webglAddon);
xterm-addon-fit
xterm-addon-fit
插件的作用是自动调整终端的行数和列数来盛满父容器。
可以通过xterm-addon-fit
插件来获取将终端盛满父容器,将xterm实例上的rows和cols返回给后端,后端用于设置终端的行数和列数,用来同步前端展示的行数列数和后端终端的一致。
如果前端和后端行数列数不一直的影响:例如在vim编辑状态,如果后端的行数少于前端的行数,vim进入编辑状态返回了首屏的内容,前端在终端上加载首屏内容,由于前端行数多于后端,就导致首屏的内容在前端的终端渲染撑不满。
需要注意的点是
xterm-addon-fit
插件需要在xterm调用了open方法后使用才会生效。
import { FitAddon } from 'xterm-addon-fit';
const _this = this;
// 终端大小自适应屏幕插件
const fitAddon = new FitAddon();
this.term.loadAddon(fitAddon);
// xterm渲染
this.term.open(this.$refs.terminal);
// 大小自适应
fitAddon.fit();
// ws发送行数和列数给后端
_this.handleSocketSendMessage({ type: 'TERMINAL_RESIZE', row: _this.term.rows, col: _this.term.cols });
// 窗口大小改变时,触发xterm的resize方法使自适应
function resizeScreen() {
fitAddon.fit();
// ws发送行数和列数给后端
_this.handleSocketSendMessage({ type: 'TERMINAL_RESIZE', row: _this.term.rows, col: _this.term.cols });
}
window.addEventListener('resize', resizeScreen);
xterm-addon-attach
xterm-addon-attach
这个插件允许终端通过 WebSocket 与远程服务器进行通信,从而实现实时数据传输和命令执行。如果使用改插件则不用通过xterm的onData来向ws发送消息,也不用通过xterm的write插入内容,改插件会全部处理ws的发送和接收。
但是xterm-addon-attach
发送的消息为按键的字符串,如果想要自定义ws发送的数据不能使用改插件,需要自己通过onData处理ws发送的数据。
注意:xterm-addon-attach 需要 xterm.js v4+
import { AttachAddon } from 'xterm-addon-attach';
const socket = new WebSocket('ws://xxx');
const attachAddon = new AttachAddon(socket);
this.term.loadAddon(attachAddon);