实现一个网页终端

先简单说一下原理吧,在网页上和服务器上建立一个ws连接,然后网页获取用户输入传给服务端,服务端解析用户输入,在服务端shell执行命令并将执行输出通过ws传给网页渲染到页面上。

以上原理说起来简单,但是完全自己实现是不太现实的。下面我把实现用到的库和插件以及使用方式简单说一下。

xterm.js

xterm.js 是一个用来实现网页上终端UI的库。

简单的使用示例:

<div id="terminal"></div>
<script>
  var terminalIns = new Terminal();
  terminalIns.open(document.getElementById('terminal'));
  terminalIns.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
</script>

node-pty

node-pty 是在node.js上用户执行shell命令,并获取标准输出的仓库,可以配合xterm.js通过ws来实现远程终端。

var os = require('os');
var pty = require('node-pty');

var shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';

var ptyProcess = pty.spawn(shell, [], {
  name: 'xterm-color',
  cols: 80,
  rows: 30,
  cwd: process.env.HOME,
  env: process.env
});

ptyProcess.on('data', function(data) {
  process.stdout.write(data);
});

ptyProcess.write('ls\r');
ptyProcess.resize(100, 40);
ptyProcess.write('ls\r');

sockjs

sockjs 这个没啥好说的,实现WebSocket的库。

const http = require('http');
const sockjs = require('sockjs');

const echo = sockjs.createServer({ prefix:'/echo' });
echo.on('connection', function(conn) {
  conn.on('data', function(message) {
    conn.write(message);
  });
  conn.on('close', function() {});
});

const server = http.createServer();
echo.attach(server);
server.listen(9999, '0.0.0.0');

实现流程

  1. 在服务端通过sockjs起一个ws的服务
  2. 并实例化node-pty通过sockjs的ws服务来接受客户端的命令执行并将反馈通过ws输出到客户端
  3. 在网页端通过xterm.js初始化一个网页终端UI
  4. 将网页端的xterm.js实例与服务端的node-pty建立连接,这里需要用到xterm.js的一个插件xterm-addon-attach这个插件接受一个WebSocket实例作为参数与服务端建立连接

code

一个完整的示例代码web-term ,有兴趣的可以看看。