【问题标题】:Build Url using ServletUriComponentsBuilder without port number in Spring在Spring中使用没有端口号的ServletUriComponentsBuilder构建Url
【发布时间】:2014-12-05 00:47:58
【问题描述】:

我在我的服务类中使用ServletUriComponentsBuilder 来构建一些 url,但问题是它还包括运行 servlet 容器的端口号,当我在代理服务器后面的生产环境中部署我的应用程序时,这是一个问题它应该只在端口 80 上运行

我使用的代码是:

String sUri = ServletUriComponentsBuilder.fromCurrentContextPath().path("/student/edit/" + st.getId()).build().toUriString();

虽然我在 JSP 中使用的 c:url 工作得非常好,但它不包括端口号。有什么方法可以让ServletUriComponentsBuilder 也开始检测它是否需要包含端口号。

表示如果应用程序在端口8080 启动,那么它可以包含端口号,但是当应用程序从端口80 访问时,则不包含?

发生了什么:如果我的 tomcat 在端口 8080 上运行,而我有代理服务器在端口 80 上提供请求,但由 ServletUriComponentsBuilder 构建的 url 仍然在主机后附加端口 8080,我需要它是 @ 987654329@

【问题讨论】:

    标签: spring spring-mvc


    【解决方案1】:

    看看ServletUriComponentsBuilder#fromRequest

    String scheme = request.getScheme();
    int port = request.getServerPort();
    String host = request.getServerName();
    
    String header = request.getHeader("X-Forwarded-Host");
    
    if (StringUtils.hasText(header)) {
        String[] hosts = StringUtils.commaDelimitedListToStringArray(header);
        String hostToUse = hosts[0];
        if (hostToUse.contains(":")) {
            String[] hostAndPort = StringUtils.split(hostToUse, ":");
            host = hostAndPort[0];
            port = Integer.parseInt(hostAndPort[1]);
        }
        else {
            host = hostToUse;
         }
    }
    ....
    

    尤其是线

    String header = request.getHeader("X-Forwarded-Host");
    

    会成功的。您所要做的就是在您的代理服务器中设置X-Forwarded-Host 并开始使用ServletUriComponentsBuilder#fromRequest 而不是ServletUriComponentsBuilder#fromCurrentContextPath。您的 url 应该包含您的公共代理主机名,并且没有端口。

    【讨论】:

    • 问题是我正在从服务类访问此方法,并且该方法中没有HttpServletRequest 对象。我知道的唯一方法是从控制器获取它并将其传递给服务类?这是正确的方法吗?
    • 这是正确的。但我不建议将 HttpServletRequest 传递到服务层。您不应该将您的服务层绑定到 Web 层。但是,只要您在服务中构建链接,这已经潜入您的代码库。提取链接构建到您的 Web 层,您的服务应该只返回一个域对象 (pojo)。您将能够在另一个上下文中重用您的服务而无需大惊小怪(Unittest、SOAP Webservices、消息传递等等)
    • 是的,你是对的,我不应该将服务层与 Web 层联系起来。我是 MVC 的新手,只有一个问题我不明白该把代码放在哪里。我需要构建一个 <String, List> 的 Map,它将作为 JSON(用于 AJAX)返回。我不知道在哪里写这段代码。如果你能给我一些建议,我会很高兴。仅在此列表中,我也将这些 URL 放入
    • 尝试自己回答。您想要返回 JSON 以响应 ajax 调用。 JSON 和 Ajax 与 Web 高度相关。你应该把你的代码放在哪里(答案很明显:-))?
    • 看起来很明显,但我真的不明白。将其放入 JSP 似乎不对,因为它只是一个 Map,一种选择是将其直接放入控制器中,这是正确的吗?但是这个MapDAO 获取数据,为此我需要在服务类中创建更多方法。这是正确的方法吗?
    【解决方案2】:

    这是这个方法的一个错误:

    public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request) {
        String scheme = request.getScheme();
        int port = request.getServerPort();
        String host = request.getServerName();
    
        String header = request.getHeader("X-Forwarded-Host");
    
        if (StringUtils.hasText(header)) {
            String[] hosts = StringUtils.commaDelimitedListToStringArray(header);
            String hostToUse = hosts[0];
            if (hostToUse.contains(":")) {
                String[] hostAndPort = StringUtils.split(hostToUse, ":");
                host  = hostAndPort[0];
                port = Integer.parseInt(hostAndPort[1]);
            }
            else {
                host = hostToUse;
            }
        }
    
        ServletUriComponentsBuilder builder = new ServletUriComponentsBuilder();
        builder.scheme(scheme);
        builder.host(host);
        if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
            builder.port(port);
        }
        builder.pathFromRequest(request);
        builder.query(request.getQueryString());
        return builder;
    }
    

    如果X-Forwarded-Host被填满了,并且没有端口,那是因为我们在80端口上。但是其他的

    else {
        host = hostToUse;
    }
    

    所以这种情况是混合情况,主机是从 X-Forwarded-Host 值中读取的,但端口是直接从请求中读取的(这是 apache 用来调用 tomcat 的请求)。 我们正在这里解决这个问题,但没有找到任何替代方法来编写新的 UriComponentsBuilder(好吧......也许只是扩展!)

    【讨论】:

    • 看看 org.springframework.hateoas.mvc.ControllerLinkBuilder 他们确实在“getBuilder()”方法中解决了这个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    相关资源
    最近更新 更多