專案需求:登入頁走 HTTPS(Port 8443),登入後其餘請求導向 HTTP(Port 8080)。但 request.getServerPort() 僅能拿到當前請求的埠(HTTPS 時為 8443),無法直接取得 HTTP 埠。解法:讀取 server.xml 中的 Connector 設定。
// Tomcat / JBoss 通用
String catalinaHome = System.getProperty("catalina.home"); // 如 /opt/tomcat
String userDir = System.getProperty("user.dir"); // 如 /opt/tomcat/bin
catalina.home 指向容器根目錄,user.dir 指向啟動工作目錄(通常是 bin)。
使用標準 DOM + XPath,定位 <Service name="Catalina"> 下第一個無 scheme 屬性(即預設 HTTP)的 Connector。
public static Integer getTomcatHttpPort(File serverXml) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(serverXml);
XPath xpath = XPathFactory.newInstance().newXPath();
// 找 Service[@name='Catalina'] 下第一個無 scheme 的 Connector @port
String expr = "/Server/Service[@name='Catalina']/Connector[not(@scheme)]/@port";
String portStr = (String) xpath.compile(expr).evaluate(doc, XPathConstants.STRING);
return (portStr != null && !portStr.isEmpty()) ? Integer.valueOf(portStr) : null;
} catch (Exception e) {
// 生產環境建議記錄日誌
return null;
}
}
呼叫範例:
File serverXml = new File(System.getProperty("catalina.home"), "conf/server.xml");
Integer httpPort = getTomcatHttpPort(serverXml); // 通常回傳 8080
| Key | 說明 | 範例 |
|---|---|---|
| java.home | JRE 安裝目錄 | /usr/lib/jvm/java-11-openjdk |
| user.dir | 啟動工作目錄 | /opt/tomcat/bin |
| catalina.home | Tomcat 根目錄 | /opt/tomcat |
| catalina.base | Tomcat 執行實例目錄(多實例時不同) | /opt/tomcat_instance1 |
| file.separator | 路徑分隔符 | / (Linux), \ (Windows) |
| line.separator | 換行符 | \n (Linux), \r\n (Windows) |
| 輸入 | getPath() | getAbsolutePath() | getCanonicalPath() |
|---|---|---|---|
| new File("abc") | abc | /home/user/abc | /home/user/abc |
| new File(".") | . | /home/user/. | /home/user |
| new File("..") | .. | /home/user/.. | /home |
getPath():單純回傳建構時的字串。getAbsolutePath():補齊絕對路徑,但不解析 . ..。getCanonicalPath():解析 . ..、符號連結,回傳唯一標準路徑(IO 開銷稍大)。public String buildHttpUrl(HttpServletRequest request, String uri) {
String scheme = "http";
int httpPort = getTomcatHttpPort(new File(System.getProperty("catalina.home"), "conf/server.xml"));
String host = request.getServerName();
String portSuffix = (httpPort == 80) ? "" : ":" + httpPort;
return scheme + "://" + host + portSuffix + uri;
}
如此即可在 HTTPS 請求中,正確導向 HTTP 埠,避免硬編碼埠號。