简体   繁体   English

获取Tomcat中http端口的对应https端口号

[英]Get corresponding https port number for http port in Tomcat

I'm trying to minimize the configuration for my webapp, and one of the things I want to remove is the port number mapping: 我正在尝试最小化我的webapp的配置,我要删除的一件事是端口号映射:

  • http: 80 -> https: 443 http:80 - > https:443
  • http: 9080 -> https: 9443 http:9080 - > https:9443

Since the configuration already exists in conf/server.xml, I don't want to duplicate these settings in my app. 由于配置已经存在于conf / server.xml中,我不想在我的应用程序中复制这些设置。 It's a pain to have to change (and remember to change) multiple config files. 必须改变(并记住改变)多个配置文件是一件痛苦的事。 Also, the app should not care what environment/container it was deployed into, as long as it supports http and https. 此外,只要它支持http和https,应用程序就不应该关心它所部署的环境/容器。

I have the following configured in my web.xml, but I need to be able to build https URLs in addition to redirecting: 我在web.xml中配置了以下内容,但除了重定向之外,我还需要能够构建https URL:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>secure</web-resource-name>
        <url-pattern>/https/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

The above block tells the servlet container to redirect http requests to its https counterpart. 上面的块告诉servlet容器将http请求重定向到其https对应项。 Obviously, Tomcat knows what connector the request came from, looks up the "redirectPort" attribute in server.xml for that connector and builds the https URL using that. 显然,Tomcat知道请求来自哪个连接器,在server.xml中查找该连接器的“redirectPort”属性并使用它构建https URL。

According to these previous/related questions, there doesn't seem to be a standard or tomcat-specific way of getting the corresponding https port for a request: 根据这些先前/相关的问题,似乎没有标准或特定于tomcat的方式来获取请求的相应https端口:

TL;DR: My question is, what ideas do you have for getting the corresponding https port number for an insecure request without explicitly configuring them in your webapp? TL; DR:我的问题是,如果没有在您的webapp中明确配置它们,您有什么想法来获取不安全请求的相应https端口号?

One idea I have is to make a http call from the webapp to itself to a path behind the security constraint using the same port number as the current request and parse the redirect location from the response. 我的一个想法是使用与当前请求相同的端口号从webapp到其自身的http调用到安全约束后面的路径,并从响应中解析重定向位置。 The responses should be cached, of course. 当然,应该缓存响应。 Is there a more straightforward way? 有更简单的方法吗?

EDIT: Added an answer with the code for the idea. 编辑:添加了与该想法的代码的答案

In case anyone wanted to know how to implement the idea I offered in the question, here's some sample code I put together to test it. 如果有人想知道如何实现我在问题中提供的想法,这里有一些示例代码,我将它们放在一起进行测试。 I don't think I'm going with this solution though. 我不认为我会使用这个解决方案。

This works with the security-constraint block from the question body. 这适用于问题正文中的安全约束块。

private static final String HTTPS_CONSTRAINED_PATH = "/https";

private static ConcurrentHashMap<String, Integer> resolvedHttpsPortMap = new ConcurrentHashMap<String, Integer>();
private static final ReentrantLock portMapLock = new ReentrantLock();

public static int resolveHttpsPort(HttpServletRequest request) {
    if (request.isSecure()) return request.getServerPort();
    String key = request.getServerName() + ":" + request.getServerPort();
    Integer port = resolvedHttpsPortMap.get(key);
    if (port == null) {
        portMapLock.lock();
        try {
            port = resolvedHttpsPortMap.get(key);
            if (port == null) {
                URL url = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath() + HTTPS_CONSTRAINED_PATH);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                if (conn.getResponseCode() != 301 && conn.getResponseCode() != 302
                        && conn.getResponseCode() != 303 && conn.getResponseCode() != 307) {
                    throw new IllegalStateException("Got unexpected response code " + conn.getResponseCode() + " from URL: " + url);
                }
                String location = conn.getHeaderField("Location");
                if (location == null) {
                    throw new IllegalStateException("Did not get a Location header in the response from URL: " + url);
                }
                URL locationUrl = new URL(location);
                port = locationUrl.getPort();
            }
        } catch (Exception e) {
            logger.warn("Could not determine corresponding HTTPS port for '" + key + "'", e);
        } finally {
            if (port == null) port = -1;
            resolvedHttpsPortMap.put(key, port);
            portMapLock.unlock();
        }
    }
    return port;
}

I don't see why you need to know the secure port numbers at all. 我不明白为什么你需要知道安全的端口号。 If the resource being accessed is marked as requiring SSL, Tomcat will send a redirect to https: and the appropriate secure port. 如果被访问的资源被标记为需要SSL,则Tomcat将重定向发送到https:和相应的安全端口。 That's what the configuration in server.xml is for. 这就是server.xml中的配置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM