java - 如何在 Spring MVC 中代理/镜像 Websocket 连接 url?
问题描述
我几乎完成了如何将服务器端 Shiny 应用程序嵌入到 JSP 页面而不将应用程序暴露在其他地方,但是这个解决方案途径的最后一部分让我真的卡住了。
(基本背景:这是一个 Spring MVC Java 网络服务器,与 Shiny 应用程序在同一台机器上。如果可能,我想避免迁移到 Spring Boot。)
该代码已成功将所有 Shiny 内容从localhost:3305
on 镜像到localhost:8080/project/shiny-proxy
,除了 websocket 连接 URL:ws://localhost:8080/project/shiny-proxy/websocket/
需要映射到ws://localhost:3305/websocket/
。http://localhost:3305/websocket/
当我在 Chrome 中访问它时返回一个硬编码的“未找到”HTML 页面,因此使用http://
前缀请求不太可能通过任何方法工作。
请注意,我希望如果我可以在客户端和 之间建立连接ws://localhost:3305/websocket/
,Java 代码将不需要处理它们之间的任何 Websocket 消息。
到目前为止,这是基于https://stackoverflow.com/a/23736527/7376471的控制器代码:
private static final RestTemplate restTemplate = new RestTemplate(
/* specific HttpRequestFactory here */);
@RequestMapping(path = "/shiny-proxy/**")
public ResponseEntity<String> mirrorRest(@RequestBody(required = false) String body,
HttpMethod method, HttpServletRequest request) throws URISyntaxException {
String path = StringUtils.removeStart(request.getRequestURI(), "/project/shiny-proxy");
boolean websocket = false;
URI uri;
if (path.endsWith("/websocket/")) {
websocket = true;
// restore the ws:// that the request URL started with after Spring MVC makes it http://
uri = new URI("ws", null, "localhost", 3305, path, request.getQueryString(), null);
} else {
uri = new URI(request.getScheme(), null, "localhost", 3305, path, request.getQueryString(), null);
}
if (websocket) {
System.out.println(request.getRequestURL().toString());
System.out.println(request.getRequestURI());
System.out.println(path);
System.out.println(uri);
}
HttpHeaders headers = new HttpHeaders();
if (path.endsWith(".css.map")) { // special handling for unusual content types from Shiny
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> ret = null;
try {
ret = restTemplate.exchange(uri, method, httpEntity, String.class);
} catch (Exception e) {
System.out.println(request.getRequestURL().toString());
System.out.println(request.getRequestURI());
System.out.println(path);
System.out.println(uri);
e.printStackTrace();
}
if (websocket) {
System.out.println("ResponseEntity headers: " + ret.getHeaders());
}
return ret;
}
但我找不到任何HttpRequestFactory
适用于ws://
URL 的东西(其中许多将 URI 转换为不支持 ws:// 的 java.net.URL,而我测试过的其他人无法处理 ws://反射代码),即使可以,我也不确定返回 aResponseEntity
是否适用于 ws 连接。
所以我的问题是,有没有办法让控制器在给定 ws:// 请求 URL 的情况下正确地在客户端和 localhost:3305 之间建立 websocket 连接,或者我应该放弃 RestTemplate 的想法并尝试像 Nginx 这样的配置代理吗?
解决方案
在我的案例中,使用配置代理的解决方案非常简单:启用Include conf/extra/httpd-vhosts.conf
in /opt/bitnami/apache2/conf/httpd.conf
,
并将 httpd-vhosts.conf 的内容设置为:
<VirtualHost *:80>
RewriteEngine on
RewriteRule /project/shiny-proxy/websocket/(.*) ws://localhost:3305/websocket/$1 [P,L]
</VirtualHost>
Bitnami 的默认配置非常好,无需进行其他更改。
推荐阅读
- android - 任务 ':sqflite:createFullJarDebug' 执行失败
- c++ - 在当前 C++ 草案的 [namespace.def]/2 中,下面突出显示的表达式 `that namespace` 指的是哪个命名空间?
- google-apis-explorer - 尝试运行文件时找不到共享驱动器:列表
- python - 强制运行特定的 python 可执行文件
- ios - 使用 Detox 测试与超时相关的测试,例如 Popups/Tooltips 等
- tensorflow - 如何在 TensorBoard 中为 TensorFlow 对象检测 API 显示纯负图像
- ios - 如何从我的 PC 在 iphone 上测试我的应用程序
- mysql-5.1 - 根据特定 id 的最新时间戳创建计数视图
- python - Python 3 中 max([a for a in [1,2]]) 和 max(a for a in [1,2]) 之间的区别
- java - 使用休眠插入两个依赖实体时出现死锁