【个人笔记】vue+xterm.js+novnc实现终端交互和远程桌面
最近公司有一个项目需要实现页面终端交互,另一个是连接VNC,终端一开始是使用webshell实现的,如果直接用webshell的话,因为是前后端分离就避免不了要用iframe去嵌套,VNC同样,所以就把webshell更换成xterm.js,VNC更换成novnc,两个插件把iframe去掉了,此处做一个记录由于xterm.js官方还是比较坑的,没什么比较完整的实例,在网上搜索的资料很多没有表明.
·
介绍一个 VNC连接工具:iis7服务器管理工具
IIs7服务器管理工具可以批量连接并管理VNC服务器
作为服务器集成管理器,它最优秀的功能就是批量管理windows与linux系统服务器、vps。能极大的提高站长及服务器运维人员工作效率。同时iis7服务器管理工具还是vnc客户端,服务器真正实现了一站式管理,可谓是非常方便。
下载地址:http://fwqglgj.iis7.net/cp/vnc/?tscc
最近公司有一个项目需要实现页面终端交互,另一个是连接VNC,终端一开始是使用webshell实现的,如果直接用webshell的话,因为是前后端分离就避免不了要用iframe去嵌套,VNC同样,所以就把webshell更换成xterm.js,VNC更换成novnc,两个插件把iframe去掉了,此处做一个记录
由于xterm.js官方还是比较坑的,没什么比较完整的实例,在网上搜索的资料很多没有表明版本号导致浪费了很多的时间,此处先说使用版本xterm.js-------3.12.0 @novnc/novnc------1.1.0
#@novnc/novnc使用还是比较简单的,网上搜索基本问题不大
#html
<div id='shell'>
<div id="screen"></div>
</div>
#先引入
import RFB from '@novnc/novnc/core/rfb'
#data参数
rfb:null,
url: 'ws://'......', //链接的url
IsClean: false, //是否已断开并不可重新连接
connectNum:0, //重连次数,
#methods
// vnc连接断开的回调函数
disconnectedFromServer (msg) {
if(msg.detail.clean){
// 根据 断开信息的msg.detail.clean 来判断是否可以重新连接
this.contentVnc()
} else {
//这里做不可重新连接的一些操作
}
},
// 连接成功的回调函数
connectedToServer() {
console.log('success')
},
//连接vnc的函数
connectVnc () {
const PASSWORD = this.pwd;
let rfb = new RFB(document.getElementById('screen'), this.url, {
// 向vnc 传递的一些参数,比如说虚拟机的开机密码等
credentials: {password: PASSWORD}
});
rfb.addEventListener('connect', this.connectedToServer);
rfb.addEventListener('disconnect', this.disconnectedFromServer);
// rfb.scaleViewport = true; //scaleViewport指示是否应在本地扩展远程会话以使其适合其容器。禁用时,如果远程会话小于其容器,则它将居中,或者根据clipViewport它是否更大来处理。默认情况下禁用。
// rfb.resizeSession = true; //是一个boolean指示是否每当容器改变尺寸应被发送到调整远程会话的请求。默认情况下禁用
this.rfb = rfb;
}
#再mounted中引用
this.connectVnc()
#自适应宽高
function changeMobsfIframe(){
const mobsf = document.getElementById('screen');
const deviceWidth = document.body.clientWidth;
const deviceHeight = document.body.clientHeight;
mobsf.style.width = 100 + '%'; //数字是页面布局宽度差值
mobsf.style.height = (Number(deviceHeight)-109) + 'px'; //数字是页面布局高度差
}
changeMobsfIframe()
window.onresize = function(){
changeMobsfIframe()
}
使用xterm.js特别小心版本,因为3.和4.版本区别还是比较大的,3.里面像fit、attach已经被拿出来了,xterm.on也更换了用法,具体的更新参考以下:https://github.com/xtermjs/xterm.js/releases/tag/4.0.0
我的配置也感谢下面这位小姐姐:
https://blog.csdn.net/weixin_38318244/article/details/103908129
#html
<div
style="height: 100%;
background: #002833;"
>
<div id="terminal" ref="terminal"></div>
</div>
#需要引入
import { Terminal } from "xterm";
import "xterm/dist/xterm.css";
import * as fit from "xterm/lib/addons/fit/fit";
import * as fullscreen from "xterm/lib/addons/fullscreen/fullscreen"; //全屏
import * as attach from "xterm/lib/addons/attach/attach";
Terminal.applyAddon(fit);
Terminal.applyAddon(attach);
Terminal.applyAddon(fullscreen); // Apply the `fullscreen` addon
#data参数
order: "",
urlParam: {
fullTag: "",
namespace: "",
podName: ""
},
shellWs: "", //ws实例
term: "", // 保存terminal实例
showOrder: "", // 保存服务端返回的命令
rows: 40,
cols: 100,
#mounted初始化配置
let _this = this;
this.rows = document.body.offsetHeight / 16 - 9;
this.cols = document.body.offsetWidth / 14;
//this.cols = 400
let term = new Terminal({
rendererType: "canvas", //渲染类型
rows: parseInt(_this.rows), //行数
cols: parseInt(_this.cols), // 不指定行数,自动回车后光标从下一行开始
convertEol: true, //启用时,光标将设置为下一行的开头
scrollback: 800, //终端中的回滚量
disableStdin: false, //是否应禁用输入。
cursorStyle: "underline", //光标样式
cursorBlink: true, //光标闪烁
theme: {
foreground: "#ffffff", //字体
background: "#002833", //背景色
cursor: "help", //设置光标
lineHeight: 16
}
});
// 换行并输入起始符“$”
term.prompt = () => {
term.write("\r\n$ ");
};
// Load WebLinksAddon on terminal, this is all that's needed to get web links
// working in the terminal.
// term.loadAddon(new WebLinksAddon());
term.open(this.$refs["terminal"]);
term.toggleFullScreen(); //全屏
window.onresize = function() {
term.fit();
term.toggleFullScreen(); //全屏
term.prompt();
}
function runFakeTerminal(_this) {
if (term._initialized) {
return;
}
term._initialized = true;
term.prompt = () => {
term.write("\r\n ");
};
term.writeln("Welcome to use Superman. ");
term.writeln(
`This is Web Terminal of pod\x1B[1;3;31m ${
_this.urlParam.podName
}\x1B[0m in namespace\x1B[1;3;31m ${_this.urlParam.namespace}\x1B[0m`
);
term.prompt();
// console.log("term", term);
// 监控键盘输入事件
// / **
// *添加事件监听器,用于按下键时的事件。事件值包含
// *将在data事件以及DOM事件中发送的字符串
// *触发了它。
// * @返回一个IDisposable停止监听。
// * /
term.on("key", function(key) {
let order = {
data: key,
status: 0
}; //重点是这里,主要还是要看清楚你的后台接收的数据是什么样的,不一定是{data:'',status:''},这个坑踩得我很惨,要看后台的接收数据!!!
_this.onSend(order);
});
term.on("paste", function(data) {
_this.order = data;
term.write(data);
});
term.on("resize", size => {
let order = {
Rows: parseInt(size.rows),
Cols: parseInt(size.cols),
Op: "resize"
};
_this.onSend(order);
});
_this.term = term;
}
runFakeTerminal(_this);
#methods
/**
* **wsShell 创建页面级别的websocket,加载页面数据
* ws 接口:/v1/task/deploy/detail/container
* 参数:无
* ws参数:
* @deployId 任务id
* @tagString 当前节点
* 返回:无
* **/
wsShell() { //记得在created中调用
const _this = this;
this.shellWs = new WebSocket('ws://.....') //建立websocket,因为xterm.js是用websocket做交互的
this.shellWs.onopen = function(){
console.log('open')
},
this.shellWs.onmessage = function(e){
let data = JSON.parse(e.data)
if (data.message == "\n" || data.message == "\r\nexit\r\n") {
_this.$message.error("连接已关闭");
}
_this.term.write(data.message);
_this.showOrder = data.message;
_this.order = "";
}
this.shellWs.onclose= function(){
_this.$message.error({
message: "ws 请求失败,请刷新重试~",
duration: 5000
});
}
},
onSend(data) {
const _this = this
// data = this.base.isObject(data) ? JSON.stringify(data) : data; //这两个具体作用在本配置没什么作用了,具体看小姐姐的用处
// data = this.base.isArray(data) ? data.toString() : data;
data = JSON.stringify(data)
data = data.replace(/\\\\/, "\\");
_this.shellWs.send(data);
},
//删除左右两端的空格
trim(str) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
更多推荐
已为社区贡献3条内容
所有评论(0)