HttpServlet 是 Servlet 開發的核心類別,封裝 HTTP 協定細節,提供豐富 API 存取請求行、Header、參數、Cookie、Session。本文透過 SnoopServlet 完整展示如何提取並呈現所有 HTTP 請求資訊,是除錯、監控、安全審計的利器。
package com.example;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.*;
import java.util.*;
@WebServlet("/snoop")
public class SnoopServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain;charset=UTF-8");
PrintWriter out = resp.getWriter();
out.println("=== Snoop Servlet ===\n");
// 1. Servlet 初始化參數
out.println("--- Servlet 初始化參數 ---");
Enumeration<String> initParams = getInitParameterNames();
while (initParams.hasMoreElements()) {
String key = initParams.nextElement();
out.println(" " + key + " = " + getInitParameter(key));
}
out.println();
// 2. Context 初始化參數
out.println("--- Context 初始化參數 ---");
ServletContext ctx = getServletContext();
Enumeration<String> ctxParams = ctx.getInitParameterNames();
while (ctxParams.hasMoreElements()) {
String key = ctxParams.nextElement();
out.println(" " + key + " = " + ctx.getInitParameter(key));
}
out.println();
// 3. Context 屬性 (應用級共享資料)
out.println("--- Context 屬性 ---");
Enumeration<String> ctxAttrs = ctx.getAttributeNames();
while (ctxAttrs.hasMoreElements()) {
String key = ctxAttrs.nextElement();
out.println(" " + key + " = " + ctx.getAttribute(key));
}
out.println();
// 4. Request 屬性 (請求級傳遞資料)
out.println("--- Request 屬性 ---");
Enumeration<String> reqAttrs = req.getAttributeNames();
while (reqAttrs.hasMoreElements()) {
String key = reqAttrs.nextElement();
out.println(" " + key + " = " + req.getAttribute(key));
}
out.println();
// 5. 基本請求資訊
out.println("--- 基本請求資訊 ---");
out.println("Servlet 名稱: " + getServletName());
out.println("協定: " + req.getProtocol());
out.println("Scheme: " + req.getScheme());
out.println("伺服器名稱: " + req.getServerName());
out.println("伺服器埠: " + req.getServerPort());
out.println("伺服器資訊: " + ctx.getServerInfo());
out.println("客戶端 IP: " + req.getRemoteAddr());
out.println("客戶端主機: " + req.getRemoteHost());
out.println("字元編碼: " + req.getCharacterEncoding());
out.println("內容長度: " + req.getContentLength());
out.println("內容類型: " + req.getContentType());
out.println("Locale: " + req.getLocale());
out.println("預設回應緩衝: " + resp.getBufferSize());
out.println();
// 6. 請求參數 (查詢字串 / 表單資料)
out.println("--- 請求參數 ---");
Enumeration<String> paramNames = req.getParameterNames();
while (paramNames.hasMoreElements()) {
String key = paramNames.nextElement();
String[] values = req.getParameterValues(key);
out.print(" " + key + " = ");
for (int i = 0; i < values.length; i++) {
out.print(values[i] + (i < values.length - 1 ? ", " : ""));
}
out.println();
}
out.println();
// 7. 請求 Header
out.println("--- 請求 Header ---");
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = headerNames.nextElement();
out.println(" " + key + ": " + req.getHeader(key));
}
out.println();
// 8. Cookie
out.println("--- Cookie ---");
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
out.println(" " + c.getName() + " = " + c.getValue()
+ " [Domain:" + c.getDomain() + ", Path:" + c.getPath()
+ ", MaxAge:" + c.getMaxAge() + ", Secure:" + c.getSecure() + "]");
}
} else {
out.println(" (無 Cookie)");
}
out.println();
// 9. 安全與認證資訊
out.println("--- 安全與認證 ---");
out.println("是否 HTTPS: " + req.isSecure());
out.println("認證類型: " + req.getAuthType());
out.println("HTTP 方法: " + req.getMethod());
out.println("遠端使用者: " + req.getRemoteUser());
out.println();
// 10. URL 解析細節
out.println("--- URL 解析 ---");
out.println("請求 URI: " + req.getRequestURI());
out.println("Context Path: " + req.getContextPath());
out.println("Servlet Path: " + req.getServletPath());
out.println("Path Info: " + req.getPathInfo());
out.println("Path Translated: " + req.getPathTranslated());
out.println("Query String: " + req.getQueryString());
out.println();
// 11. Session 完整資訊
out.println("--- Session ---");
HttpSession session = req.getSession(false); // 不自動建立
if (session != null) {
out.println("請求 Session ID: " + req.getRequestedSessionId());
out.println("當前 Session ID: " + session.getId());
out.println("建立時間: " + new Date(session.getCreationTime()));
out.println("最後存取: " + new Date(session.getLastAccessedTime()));
out.println("最大閒置秒數: " + session.getMaxInactiveInterval());
out.println("Session 屬性:");
Enumeration<String> sessAttrs = session.getAttributeNames();
while (sessAttrs.hasMoreElements()) {
String key = sessAttrs.nextElement();
out.println(" " + key + " = " + session.getAttribute(key));
}
} else {
out.println(" (無有效 Session)");
}
}
}
| 類別 | 核心方法 | 用途 |
|---|---|---|
| 初始化參數 | getInitParameterNames(), getInitParameter(String) | 部署時靜態配置 (web.xml/@WebServlet initParams) |
| Context 參數/屬性 | getServletContext() → getInitParameter*, getAttribute* | 應用級共享配置與物件 (資料源、快取、全域設定) |
| Request 參數 | getParameterNames(), getParameterValues(String), getParameterMap() | 查詢字串、表單提交、multipart (需 @MultipartConfig) |
| Request Header | getHeaderNames(), getHeader(String), getHeaders(String) | User-Agent、Referer、Authorization、Content-Type 等 |
| Cookie | getCookies() → Cookie[] | 客戶端狀態管理、追蹤、偏好設定 |
| URL 解析 | getRequestURI(), getContextPath(), getServletPath(), getPathInfo(), getQueryString() | 路由、RESTful 參數提取、重寫 |
| Session | getSession(boolean), getAttribute/putAttribute, invalidate() | 伺服器端會話狀態、購物車、登入憑證 |
RemoteAddr、User-Agent、Referer、Authorization 偵測異常存取。Content-Length、Header 數量、Cookie 大小評估頻寬開銷。在 web.xml 或 @WebServlet 設定初始化參數:
@WebServlet(
urlPatterns = "/snoop",
initParams = {
@WebInitParam(name = "adminEmail", value = "admin@example.com"),
@WebInitParam(name = "maxRows", value = "100")
}
)
Context 參數在 web.xml:
<context-param>
<param-name>appName</param-name>
<param-value>MyApp</param-value>
</context-param>
掌握 HttpServletRequest 完整 API,等於掌握 HTTP 請求的每一個細節。搭配 Filter/Interceptor 可在控制器前統一記錄、驗證、轉換請求資料,構建健壯的 Web 應用基礎設施。