feat: 优化rdp连接

This commit is contained in:
chaoszhu
2025-10-25 10:33:31 +08:00
parent 334c9d3de7
commit 3b540d2993
7 changed files with 146 additions and 44 deletions
+28
View File
@@ -0,0 +1,28 @@
const { createProxyMiddleware } = require('http-proxy-middleware')
/**
* RDP代理中间件
* 将/rdp-proxy/guac路径的请求代理到RDP独立端口
*/
const createRdpProxyMiddleware = () => {
const RDP_PORT = process.env.RDP_PORT || 8083
const RDP_HOST = process.env.RDP_HOST || '127.0.0.1' // 使用127.0.0.1更可靠
const target = `http://${ RDP_HOST }:${ RDP_PORT }`
console.log('Creating RDP proxy middleware with target:', target)
// 创建WebSocket代理
const wsProxy = createProxyMiddleware({
target: target,
ws: true,
changeOrigin: true,
pathRewrite: {
'^/rdp-proxy': ''
},
logLevel: 'debug'
})
return wsProxy
}
module.exports = createRdpProxyMiddleware
+48
View File
@@ -0,0 +1,48 @@
const http = require('http')
const GuacamoleLite = require('guacamole-lite')
const RDP_PORT = process.env.RDP_PORT || 8083 // 使用独立端口
const GUACD_HOST = process.env.GUACD_HOST || 'guacd'
const GUACD_PORT = Number(process.env.GUACD_PORT) || 4822
// 创建独立的HTTP服务器用于RDP
const rdpServer = http.createServer()
const websocketOptions = {
server: rdpServer,
path: '/guac'
}
const guacdOptions = {
host: GUACD_HOST,
port: GUACD_PORT
}
const clientOptions = {
crypt: {
cypher: 'AES-256-CBC',
key: global.rpdToken || Array.from({ length:32 },()=>Math.random().toString(36)[2]).join('')
}
}
const startRdpServer = () => {
try {
const guacamole = new GuacamoleLite(websocketOptions, guacdOptions, clientOptions)
guacamole.on('connection', () => {
consola.success('✔ RDP guacamole连接成功')
})
guacamole.on('error', (err) => {
consola.error('❌ RDP guacamole连接错误', err)
})
rdpServer.listen(RDP_PORT, () => {
consola.success(`RDP服务运行在端口: ${ RDP_PORT }`)
})
} catch (error) {
consola.error('❌ RDP 初始化失败:', error.message)
}
}
module.exports = { startRdpServer }
+17 -2
View File
@@ -3,7 +3,7 @@ const compose = require('koa-compose') // 组合中间件,简化写法
const http = require('http')
const { httpPort } = require('./config')
const middlewares = require('./middlewares')
const wsRdp = require('./socket/rdp')
const { startRdpServer } = require('./rdp-server')
const wsTerminal = require('./socket/terminal')
const wsSftpV2 = require('./socket/sftp-v2')
const wsDocker = require('./socket/docker')
@@ -15,17 +15,32 @@ const { throwError } = require('./utils/tools')
const httpServer = () => {
const app = new Koa()
const server = http.createServer(app.callback())
// 添加RDP WebSocket代理
const createRdpProxyMiddleware = require('./middlewares/rdp-proxy')
const rdpProxy = createRdpProxyMiddleware()
// 只处理WebSocket升级请求的代理(RDP只需要WebSocket)
server.on('upgrade', (request, socket, head) => {
if (request.url.startsWith('/rdp-proxy')) {
rdpProxy.upgrade(request, socket, head)
}
})
serverHandler(app, server)
// ws一直报跨域的错误:参照官方文档使用createServer API创建服务
server.listen(httpPort, () => {
consola.success(`Server(http) is running on: http://localhost:${ httpPort }`)
})
// 启动独立的RDP服务
startRdpServer()
}
// 服务
function serverHandler(app, server) {
app.proxy = true // 用于nginx反代时获取真实客户端ip
wsRdp(server) // RDP
wsTerminal(server) // 终端
wsSftpV2(server) // sftp-v2
wsDocker(server) // docker
-40
View File
@@ -1,40 +0,0 @@
const GuacamoleLite = require('guacamole-lite')
const GUACD_HOST = process.env.GUACD_HOST || 'guacd'
const GUACD_PORT = Number(process.env.GUACD_PORT) || 4822
const getOptions = (server) => {
const websocketOptions = {
server,
path: '/guac'
}
const guacdOptions = {
host: GUACD_HOST,
port: GUACD_PORT
}
const clientOptions = {
crypt: {
cypher: 'AES-256-CBC',
key: global.rpdToken
}
}
return { websocketOptions, guacdOptions, clientOptions }
}
module.exports = (httpServer) => {
const { websocketOptions, guacdOptions, clientOptions } = getOptions(httpServer)
let guacamole = new GuacamoleLite(websocketOptions, guacdOptions, clientOptions)
try {
guacamole.on('connection', () => {
consola.success('✔ RDP guacamole连接成功')
})
guacamole.on('error', (err) => {
consola.error('❌ RDP guacamole连接错误', err)
})
} catch (error) {
guacamole.close()
guacamole = null
consola.error('❌ RDP 初始化失败:', error.message)
}
}
+1
View File
@@ -29,6 +29,7 @@
"fs-extra": "^11.2.0",
"global": "^4.4.0",
"guacamole-lite": "^1.2.0",
"http-proxy-middleware": "^3.0.5",
"iconv-lite": "^0.6.3",
"jsonwebtoken": "^9.0.2",
"koa": "2.16.2",
+1 -1
View File
@@ -371,7 +371,7 @@ const getRdpWsUrl = async () => {
const { data } = await $api.getRdpToken({ hostId: hostId.value, width, height })
if (!data) return $message.error('获取RDP WS URL失败')
const wsHost = $isDev ? `ws://${ location.hostname }:8082` : location.origin.replace('http', 'ws')
return `${ wsHost }/guac?token=${ encodeURIComponent(data) }`
return `${ wsHost }/rdp-proxy/guac?token=${ encodeURIComponent(data) }`
}
const connectRdp = async () => {
+51 -1
View File
@@ -1278,6 +1278,13 @@
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
"@types/http-proxy@^1.17.15":
version "1.17.17"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.17.tgz#d9e2c4571fe3507343cb210cd41790375e59a533"
integrity sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==
dependencies:
"@types/node" "*"
"@types/keygrip@*":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.6.tgz#1749535181a2a9b02ac04a797550a8787345b740"
@@ -2294,6 +2301,13 @@ debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3,
dependencies:
ms "^2.1.3"
debug@^4.3.6:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
debug@~4.3.1, debug@~4.3.2, debug@~4.3.4:
version "4.3.5"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
@@ -2823,6 +2837,11 @@ eventemitter3@^3.0.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
eventemitter3@^4.0.0:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
exsolve@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.4.tgz#7de5c75af82ecd15998328fbf5f2295883be3a39"
@@ -2919,6 +2938,11 @@ flatted@^3.2.7, flatted@^3.2.9:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
follow-redirects@^1.0.0:
version "1.15.11"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340"
integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==
follow-redirects@^1.15.6:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
@@ -3296,6 +3320,27 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-proxy-middleware@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz#9dcde663edc44079bc5a9c63e03fe5e5d6037fab"
integrity sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==
dependencies:
"@types/http-proxy" "^1.17.15"
debug "^4.3.6"
http-proxy "^1.18.1"
is-glob "^4.0.3"
is-plain-object "^5.0.0"
micromatch "^4.0.8"
http-proxy@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"
http-signature@~1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f"
@@ -3519,6 +3564,11 @@ is-path-inside@^3.0.3:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-regex@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22"
@@ -4084,7 +4134,7 @@ methods@^1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
micromatch@^4.0.5:
micromatch@^4.0.5, micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==