背景
用户需要通过前端HTML页面的noVNC(noVNC是什么?)客户端连接底层VNC Server服务端,为了防止VNC Server的IP暴露,因此需要做一层代理。正常情况下使用Nginx、Apache等都可以搞定,但是由于项目架构的一些问题,暂时不能再加一台反向代理服务器,所以决定写一个单独的模块实现反向代理的功能。
在网上和Github上找了一下,使用了HTTP-Proxy-Servlet,引入该依赖搭建一个Spring Boot项目。
搭建
引入代理的依赖
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.12</version>
</dependency>
通过注册bean拦截指定URL路径进行自定义操作
@Configuration
public class ProxyServletConfiguration {
// 拦截所有请求交给下面的VNCProxyServlet去处理
private final static String SERVLET_URL = "
@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);
}
@OnError
public void onError(Session session, Throwable error) {
logger.error("用户错误原因:"+error.getMessage());
error.printStackTrace();
}
}
都是很常用的websocket服务端的代码,唯一要注意的是前端请求'/websockify'地址发起websocket连接时,要注意用ip,尤其是本地,使用localhost会报错,要使用127.0.0.1。最后测试连接成功,返回状态码101,并且消息可以正常接收。noVNC网页端与代理模块建立websocket通信完成。
2.代理模块与VNC Server建立websocket通信
java后台作为websocket客户端很少,大多是用Netty去写的,但是不适合目前的情况,最后还是找到了一个感觉比较合适的
public class MyWebSocketClient {
public static WebSocketClient mWs;
public static void main(String[] args) {
try {
//
String url = "ws://172.28.132.11:8888/websocketify";
URI uri = new URI(url);
HashMap<String, String> httpHeadersMap = new HashMap<>();
httpHeadersMap.put("Sec-WebSocket-Version", "13");
httpHeadersMap.put("Sec-WebSocket-Key", "YBhzbbwLI83U5EH8Tlutwg==");
httpHeadersMap.put("Connection","Upgrade");
httpHeadersMap.put("Upgrade","websocket");
httpHeadersMap.put("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36");
httpHeadersMap.put("Cookie","token=8asda2das-84easdac-asdaqwe4-2asda-asdsadas");
httpHeadersMap.put("Sec-WebSocket-Extensions","permessage-deflate; client_max_window_bits");
mWs = new WebSocketClient(uri,httpHeadersMap){
@Override
public void onOpen(ServerHandshake serverHandshake) {
System.out.println("open...");
System.out.println(serverHandshake.getHttpStatus());
mWs.send("666");
}
@Override
public void onMessage(String s) {
System.out.println(s);
}
@Override
public void onClose(int i, String s, boolean b) {
System.out.println("close...");
System.out.println(i);
System.out.println(s);
System.out.println(b);
}
@Override
public void onError(Exception e) {
System.out.println("发生了错误...");
}
};
mWs.connect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 调用后报错 直接关闭了连接 状态码为1002
// close...
// 1002
// Invalid status code received: 400 Status line: HTTP/1.1 400 Client must support 'binary' or 'base64' protocol
发生错误后,发现关键地方,客户端必须支持 binary或base64协议,一番搜索后再Stack Overflow找到了线索,并且是Kanaka(noVNC和websockify的开发者)亲自回答的,大概意思就是你需要在构造函数中提供这些协议。
然后我又在websockify.js的源码中找到了这个构造,确实需要传递一个protocols的数组参数,可是这是前端,并不知道Java如何完成这个操作。
后续
首先再次感谢开源项目和各位博主大佬的分享,依旧在寻找解决方案......
到此这篇关于Springboot实现VNC的反向代理功能的文章就介绍到这了,更多相关Springboot反向代理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!