首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Web 獲取請求 URL 與伺服器根路徑的標準方法

     編輯:Java 相關知識

在 Servlet/JSP 開發中,準確拼裝完整請求 URL 或生成資源絕對路徑 (CSS/JS/圖片) 是基礎技能。本文梳理 HttpServletRequest 核心 API、各路徑組成部分、典型應用場景與避坑指南。

核心 API 對照表

| 方法 | 回傳值範例 | 說明 | |------|------------|------| | getScheme() | http / https | 協議 | | getServerName() | localhost / 192.168.1.100 | 主機名或 IP | | getServerPort() | 8080 | 端口 (標準 80/443 會被容器隱藏) | | getContextPath() | /myapp / "" (ROOT) | Web 應用上下文路徑 | | getServletPath() | /user/login | Servlet 映射路徑 | | getPathInfo() | /extra/path | 額外路徑 (通配符映射時) | | getQueryString() | id=1&name=test | 查詢字串 (不含 ?) | | getRequestURI() | /myapp/user/login | contextPath + servletPath + pathInfo | | getRequestURL() | https://host:port/myapp/user/login | **完整 URL (不含查詢字串)** |

拼裝完整請求 URL (含查詢字串)

public static String getFullRequestUrl(HttpServletRequest request) {
    StringBuilder url = new StringBuilder();
    url.append(request.getScheme()).append("://")
       .append(request.getServerName());
    int port = request.getServerPort();
    if (port != 80 && port != 443) { // 標準端口不顯示
        url.append(":").append(port);
    }
    url.append(request.getRequestURI()); // 已包含 contextPath + servletPath + pathInfo
    String query = request.getQueryString();
    if (query != null) {
        url.append("?").append(query);
    }
    return url.toString();
}

生成基礎路徑 (BasePath) 用於 JSP/Thymeleaf 資源引用

<%-- JSP 經典寫法 --%>
<%
    String basePath = request.getScheme() + "://" 
                    + request.getServerName() 
                    + (request.getServerPort() == 80 ? "" : ":" + request.getServerPort())
                    + request.getContextPath() + "/";
%>
<head>
    <base href="<%=basePath%>">
    <link rel="stylesheet" href="static/css/app.css">
    <script src="static/js/app.js"></script>
</head>


    
    
    

實戰場景對比:ROOT 應用 vs 非 ROOT 應用

| 部署方式 | contextPath | servletPath (請求 /myapp/user/login?id=1) | getRequestURI() | |----------|------------------------|---------------------------------------------------------------|----------------------------| | 非 ROOT (contextPath=/myapp) | /myapp | /user/login | /myapp/user/login | | ROOT (contextPath=="") | "" | /myapp/user/login | /myapp/user/login | > **注意**:ROOT 部署時,servletPath 會包含原本屬於 contextPath 的部分,**永遠用 getRequestURI() 取得統一路徑**,不要手動拼 contextPath + servletPath。

反向代理 / 負載均衡下的陷阱與修正

Nginx/Apache 反向代理後,getServerName() 可能回傳內網 IP,getServerPort() 可能是 8080 而非 443。需啟用 Forwarded / X-Forwarded-* 標頭並配置容器:

// Spring Boot application.yml
server:
  forward-headers-strategy: framework # 或 native
  tomcat:
    remoteip:
      remote-ip-header: X-Forwarded-For
      protocol-header: X-Forwarded-Proto
      port-header: X-Forwarded-Port

或手動修正:

String scheme = request.getHeader("X-Forwarded-Proto") != null ? 
                request.getHeader("X-Forwarded-Proto") : request.getScheme();
String serverName = request.getHeader("X-Forwarded-Host") != null ?
                request.getHeader("X-Forwarded-Host") : request.getServerName();
int serverPort = request.getHeader("X-Forwarded-Port") != null ?
                Integer.parseInt(request.getHeader("X-Forwarded-Port")) : request.getServerPort();

常見錯誤與最佳實踐

錯誤寫法問題正確做法
request.getRequestURL().toString() + "?" + request.getQueryString()getRequestURL 回傳 StringBuffer,toString() 後再拼接效率低用 StringBuilder 一次組裝,或直接用 request.getRequestURI()
硬編碼 https://localhost:8080部署環境變更即失效動態取得 scheme/host/port/contextPath
忽略標準端口 80/443URL 顯示 :80、:443 不美觀判斷端口後決定是否拼接
在 Filter 中用 request.getRequestURI() 做權限匹配未排除 contextPath 導致規則失效用 request.getServletPath() 或手動移除 contextPath

總結

  • 完整 URL:getRequestURL() + getQueryString() (或手動組裝更可控)。
  • 資源基礎路徑:scheme://host:port/contextPath/,JSP 用 <base>,現代模板引擎用 @{/}。
  • 反向代理環境:務必配置 Forwarded Headers 策略,否則生成的 URL 會指向內網位址。
  • 統一工具類:專案建立 WebUtils.getFullUrl(request) / WebUtils.getBasePath(request),避免分散重複代碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved