栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot实现VNC的反向代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot实现VNC的反向代理

“targetUri”, “null”, //这里写null是因为targetUri是在自定义的VNCProxyServlet类中动态传入的,而且这里必须要有值

ProxyServlet.P_LOG, “true”,

ProxyServlet.P_PRESERVEHOST,“true”,

ProxyServlet.P_PRESERVEcookieS,“true”

);

servletRegistrationBean.setInitParameters(params);

return servletRegistrationBean;

}

}

这里遇到的坑:

​ 刚开始其实是准备在已有的一个模块中加上这个代理功能,因为可以指定拦截的路径,比如只拦截请求路径为**/proxyproxy***,这样所有请求到这个模块的都会被代理。

  1. 自定义Servlet实现动态代理目标地址

// VNCProxyServlet继承了ProxyServlet 重写了service方法 在方法中添加自定义操作 从请求地址中动态获取

@Override

protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException {

// 获取请求地址

String targetUri = servletRequest.getRequestURL().toString();

// 正则取请求地址中的参数 参数是放在域名中的

Matcher matcher = DOMAIN_REX.matcher(targetUri);

if(!matcher.find()){

// 自定义的异常

throw new GenericException(“从域名中获取vmId异常!”);

}

// 取域名中的第一个 eg: http://vmId.xxx.cn得 [vmId,xxx,cn] 得 vmId

Long vmId = Long.valueOf(matcher.group().split(".")[0]);

// eg:业务逻辑根据vmId去拿 targetUri

targetUri = vmService.getTargetUrl(vmId);

if (StringUtils.isEmpty(targetUri)) {

throw new GenericException(“代理路径不正确,请确认路径”);

}

// 设置Url

if (servletRequest.getAttribute(ATTR_TARGET_URI) == null) {

servletRequest.setAttribute(ATTR_TARGET_URI, targetUri);

}

// 设置Host

if (servletRequest.getAttribute(ATTR_TARGET_HOST) == null) {

URL trueUrl = URLUtil.url(targetUri);

servletRequest.setAttribute(ATTR_TARGET_HOST, new HttpHost(trueUrl.getHost(), trueUrl.getPort(), trueUrl.getProtocol()));

}

// 下面大部分都是父类的源码 没有需要特别修改的地方

String method = servletRequest.getMethod();

// 替换多余路径

String proxyRequestUri = this.rewriteUrlFromRequest(servletRequest);

HttpRequest proxyRequest;

if (servletRequest.getHeader(HttpHeaders.CONTENT_LENGTH) != null ||

servletRequest.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) {

proxyRequest = new BasicHttpRequest(method, proxyRequestUri);

} else {

proxyRequest = this.newProxyRequestWithEntity(method, proxyRequestUri, servletRequest);

}

this.copyRequestHeaders(servletRequest, proxyRequest);

setXForwardedForHeader(servletRequest, proxyRequest);

HttpResponse proxyResponse = null;

try {

// Execute the request

proxyResponse = this.doExecute(servletRequest, servletResponse, proxyRequest);

// Process the response

int statusCode = proxyResponse.getStatusLine().getStatusCode();

// “reason phrase” is deprecated but it’s the only way to pass

servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase());

// copying response headers to make sure SESSIonID or other cookie which comes from remote server

// will be saved in client when the proxied url was redirected to another one.

copyResponseHeaders(proxyResponse, servletRequest, servletResponse);

if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) {

servletResponse.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0);

} else {

copyResponseEntity(proxyResponse, servletResponse, proxyRequest, servletRequest);

}

} catch (Exception e) {

handleRequestException(proxyRequest, proxyResponse, e);

} finally {

if (proxyResponse != null) {

EntityUtils.consumeQuietly(proxyResponse.getEntity());

}

}

}

​ 这里主要列出关键部分,因为方案还没有完结。

  • 问题

​ 本以为这样就成功了,但是测试之后发现页面和静态资源都代理过去了,但是有一个websocket请求失败了。像noVNC这种网页版的黑窗口,早就该想到肯定是用websocket这种长链接的请求进行交互的。后来去搜了一下这个叫websockify的请求,就是最开始介绍noVNC博客中介绍的:

​ 浏览器不支持VNC,所以不能直接连接VNC,但是可以使用代理,使用noVNC通过WebSocket建立连接,而VNC Server不支持WebSocket,所以需要开启Websockify代理来做WebSocket和TCP Socket之间的转换,这个代理在noVNC的目录里,叫做websockify。

​ 此时项目是能够拦截到websockify这个请求的,但是由于servlet把这个请求当成普通的请求去代理到目标服务器,这样是无法成功的,所以要做的就是类似实现一个websocket的反向代理,搜了一下的话发现例子不是很多,大多都是在前端做的,前端作为客户端与服务端建立websocket连接,但目前的状况很明显是需要这个代理模块既做websocket服务端与web端建立连接,再作为websocket客户端与VNC 服务端建立连接,然后进行交互传递通信。

​ 后面也找到了这篇博

【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】

浏览器打开:qq.cn.hn/FTf 免费领取

客[通过noVNC和websockify连接到QEMU/KVM](

),然后总结一下从用户发出请求到得到响应的流程:

PC Chrome(客户端) => noVNC Server(noVNC端) => websockify(websocket转TCP Socket) => VNC Server(VNC服务端) => websockify(TCP Socket转websocket) => noVNC Server(noVNC端)=> PC Chrome(客户端)

用户使用PC Chrome浏览器请求 noVNC端(因为无法直接访问VNC Server端,VNC Server是不支持Websocket连接),经由websockify将websocket转为TCP Socket请求到VNC服务端,返回TCP响应,经由websockify转换为websocket返回给客户端浏览器,这样来进行交互。整个过程 websockify 代理器是关键,noVNC 可以被放在浏览器端。

  1. noVNC网页端与代理模块建立websocket通信

@Configuration

public class WebSocketConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

}

@ServerEndpoint("/websockify")

@Component

public class WebSocketServer {

@OnOpen

public void onOpen(Session session) {

logger.info(“open…”);

}

@OnClose

public void onClose() {

logger.info(“close…”);

}

@OnMessage

public void onMessage(String message, Session session) {

logger.info(message);

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/358221.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号