首页 > 解决方案 > 如何在不将应用程序暴露在其他地方的情况下将服务器端 Shiny 应用程序嵌入到 JSP 页面中

问题描述

我有一个 Shiny 应用程序,我想将它嵌入到托管在 Amazon AWS 上的 Java 8 网络服务器的页面中。(注意:我说“嵌入”是因为网络服务器中的大多数页面共享一个公共侧边栏和页脚 - 这会自动应用于大多数视图,因此 .jsp 文件只需为页面的真实内容提供 html)。

Shiny 应用程序在 3305 上侦听,网络服务器在 localhost 上托管到 :8080([server ip]/subject/index.html 可以正常通过其他机器获取网页)。

通过包含 的 shiny.jsp 嵌入 Shiny 应用程序对 localhost 来说效果很好<iframe src="http://localhost:3305">,但是当从另一台机器查看时,该页面仅在该另一台机器上查找闪亮的服务器,而它应该在主机上查找。去掉“http://”会导致 Shiny 应用程序永远不会收到请求并且页面保持空白,并且将“localhost”与“127.0.0.1”交换会导致没有明显的变化。

该服务器使用 Spring、JSTL 和 Apache Tomcat 7.0。

我不能简单地移植 Shiny 应用程序以使其在服务器外部可见,因为该应用程序显示机密信息。在 .jsp 中,这不是问题,因为 iframe 可以包装在<security:authorize>标签中(网站首先需要登录才能访问任何页面)。

问题是,将 Shiny 应用程序嵌入到 .jsp 页面中的最简单方法是什么,以使其对用户保持交互但又安全(在没有服务器外部授权的情况下无法直接访问)并且不需要额外的登录?

标签: htmlspring-mvciframespring-securityshiny

解决方案


一个 la spring mvc rest service redirect / forward / proxy,一个 Controller 镜像 Shiny 应用,这样我们就保留了访问控制:

import java.net.URI;
import java.util.Arrays;    
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

@Controller
public class ShinyController
{
    private static final RestTemplate restTemplate = new RestTemplate();

    @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");
        URI uri = new URI(request.getScheme(), null, "localhost", 3305,
                          path, request.getQueryString(), null);

        HttpHeaders headers = new HttpHeaders();
        if (path.endsWith(".css.map")) {
            headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        }
        HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
        return restTemplate.exchange(uri, method, httpEntity, String.class);
    }
}

这将处理闪亮页面的 HTML 及其所有资源。在 JSP 视图中,

<iframe src="shiny-proxy/">

现在我们只需要处理 ws://[shiny url]/websocket/ 请求。

在 web.xml 中,防止网络服务器通过以下方式处理它:

<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>/project/shiny-proxy/websocket/</url-pattern>
</servlet-mapping>

然后,启用Include conf/extra/httpd-vhosts.conf,/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>

所以...原来很简单。


推荐阅读