【问题标题】:How to proxy/mirror a Websocket connection url in Spring MVC?如何在 Spring MVC 中代理/镜像 Websocket 连接 url?
【发布时间】:2019-03-23 15:43:45
【问题描述】:

我几乎完成了How can I embed a server-side Shiny app into a JSP page without exposing the app elsewhere,但这个解决方案的最后一部分让我真的卡住了。

(基本背景:这是一个 Spring MVC Java 网络服务器,与 Shiny 应用程序在同一台机器上。如果可能,我想避免迁移到 Spring Boot。)

代码成功地将所有 Shiny 内容从 localhost:3305 镜像到 localhost:8080/project/shiny-proxy,除了 websocket 连接 URL:ws://localhost:8080/project/shiny-proxy/websocket/ 需要映射到 ws://localhost:3305/websocket/。当我在 Chrome 中访问http://localhost:3305/websocket/ 时,它会返回一个硬编码的“未找到”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;
}

但我找不到任何与ws:// URL 一起使用的HttpRequestFactory(其中许多将 URI 转换为不支持 ws:// 的 java.net.URL,以及我测试过的其他 URL无法处理反射代码中的 ws://),即使可以,我也不确定返回 ResponseEntity 是否适用于 ws 连接。

所以我的问题是,有没有办法让控制器在给定 ws:// 请求 URL 的情况下正确地在客户端和 localhost:3305 之间建立 websocket 连接,或者我应该放弃 RestTemplate 的想法并尝试像这样配置的代理用 Nginx 代替?

【问题讨论】:

    标签: java spring-mvc servlets websocket spring-rest


    【解决方案1】:

    在我的案例中,使用配置代理的解决方案非常简单: 在/opt/bitnami/apache2/conf/httpd.conf中启用Include conf/extra/httpd-vhosts.conf

    并将 httpd-vhosts.conf 的内容设置为:

    <VirtualHost *:80>
      RewriteEngine on
      RewriteRule /project/shiny-proxy/websocket/(.*) ws://localhost:3305/websocket/$1 [P,L]
    </VirtualHost>
    

    Bitnami 的默认配置非常好,无需进行其他更改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      相关资源
      最近更新 更多