HttpServletResponse
對象是由 Servlet 容器創建并傳遞給 Servlet 的 service()
方法(以及間接傳遞給 doGet()
, doPost()
等方法)的。它的核心作用是讓 Servlet 能夠向客戶端(通常是瀏覽器)發送 HTTP 響應。
通過 HttpServletResponse
對象,我們可以:
- 設置響應狀態碼 (Status Code)
- 設置響應頭 (Headers)
- 設置 Cookie
- 寫入響應體 (Response Body),即發送內容回瀏覽器
下面我們詳細看看如何進行這些操作:
1. 設置響應狀態碼 (Status Code)
狀態碼告訴瀏覽器請求的處理結果(例如,成功、未找到、服務器錯誤等)。
-
方法:
response.setStatus(int sc)
: 設置指定的 HTTP 狀態碼。response.sendError(int sc)
: 發送一個指定的狀態碼給客戶端(通常會附帶一個簡單的錯誤頁面)。response.sendError(int sc, String msg)
: 發送一個指定的狀態碼和一條錯誤消息給客戶端。response.sendRedirect(String location)
: 發送一個重定向響應 (狀態碼 302) 到指定的 URL。
-
常量:
javax.servlet.http.HttpServletResponse
接口定義了很多常用的狀態碼常量,例如:HttpServletResponse.SC_OK
(200)HttpServletResponse.SC_CREATED
(201)HttpServletResponse.SC_NO_CONTENT
(204)HttpServletResponse.SC_MOVED_PERMANENTLY
(301)HttpServletResponse.SC_FOUND
(302) -sendRedirect
默認使用這個HttpServletResponse.SC_BAD_REQUEST
(400)HttpServletResponse.SC_UNAUTHORIZED
(401)HttpServletResponse.SC_FORBIDDEN
(403)HttpServletResponse.SC_NOT_FOUND
(404)HttpServletResponse.SC_INTERNAL_SERVER_ERROR
(500)
-
示例:
// 設置成功狀態碼 response.setStatus(HttpServletResponse.SC_OK);// 如果資源未找到 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "The requested resource was not found.");// 重定向到另一個頁面 // response.sendRedirect("http://www.example.com/newPage");
注意: 設置狀態碼或調用
sendError
/sendRedirect
應該在向響應體寫入任何內容 之前 進行。
2. 設置響應頭 (Headers)
響應頭包含關于響應的元數據,例如內容類型、緩存控制、自定義信息等。
-
方法:
response.setHeader(String name, String value)
: 設置一個具有給定名稱和值的頭。如果該頭已存在,則新值將覆蓋舊值。response.addHeader(String name, String value)
: 添加一個具有給定名稱和值的頭。允許同一個頭名稱有多個值。response.setContentType(String type)
: 設置響應內容的 MIME 類型(例如 “text/html”, “application/json”, “image/jpeg”)。這實際上是設置Content-Type
頭的一個便捷方法。response.setCharacterEncoding(String charset)
: 設置發送到客戶端的響應的字符編碼(例如 “UTF-8”)。通常與setContentType
一起使用,或者直接在setContentType
中指定,如response.setContentType("text/html; charset=UTF-8");
。response.setContentLength(int len)
/response.setContentLengthLong(long len)
: 設置響應體的長度(以字節為單位)。
-
示例:
// 設置內容類型為 HTML,并使用 UTF-8 編碼 response.setContentType("text/html; charset=UTF-8"); // 或者分兩步: // response.setContentType("text/html"); // response.setCharacterEncoding("UTF-8");// 設置自定義頭 response.setHeader("X-Custom-Info", "This is my custom header value");// 設置緩存控制,禁止緩存 response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1 response.setHeader("Pragma", "no-cache"); // HTTP 1.0 response.setDateHeader("Expires", 0); // Proxies// 如果你知道響應體的確切字節數 // byte[] responseBodyBytes = ...; // response.setContentLength(responseBodyBytes.length);
注意: 設置響應頭也應該在向響應體寫入任何內容 之前 進行。
3. 設置 Cookie
Cookie 是服務器發送到用戶瀏覽器并保存在本地的一小塊數據,它們會在瀏覽器下次向同一服務器發起請求時被攜帶并發送到服務器上。
-
步驟:
- 創建一個
javax.servlet.http.Cookie
對象。 - 可選地,設置 Cookie 的屬性 (如過期時間
setMaxAge()
, 路徑setPath()
, 域setDomain()
, 安全性setSecure()
,setHttpOnly()
,setSameSite()
)。 - 使用
response.addCookie(Cookie cookie)
將 Cookie 添加到響應中。這會生成一個Set-Cookie
響應頭。
- 創建一個
-
示例:
// 創建一個新的 Cookie Cookie userCookie = new Cookie("username", "john_doe");// 設置 Cookie 的有效期為 1 小時 (3600 秒) userCookie.setMaxAge(3600);// 設置 Cookie 的路徑,使其對整個應用可見 userCookie.setPath(request.getContextPath() + "/"); // 或者簡單地 "/"// (可選) 設置為 HttpOnly,防止 JavaScript 訪問,增強安全性 userCookie.setHttpOnly(true);// (可選) 設置為 Secure,僅通過 HTTPS 傳輸 // userCookie.setSecure(true);// (可選,現代瀏覽器推薦) 設置 SameSite 屬性 // userCookie.setSameSite("Lax"); // 或 "Strict" 或 "None" (None 需要 Secure=true)// 將 Cookie 添加到響應中 response.addCookie(userCookie);// 刪除一個 Cookie (通過設置 maxAge 為 0) // Cookie deleteCookie = new Cookie("old_cookie_name", ""); // deleteCookie.setMaxAge(0); // deleteCookie.setPath("/"); // response.addCookie(deleteCookie);
注意: 添加 Cookie 也是通過設置響應頭 (
Set-Cookie
) 實現的,所以也應該在向響應體寫入任何內容 之前 進行。
4. 將內容發送回瀏覽器 (寫入響應體)
一旦狀態碼和頭信息設置完畢,你就可以開始向響應體寫入實際內容了。你有兩種方式獲取輸出流:
response.getWriter()
: 返回一個java.io.PrintWriter
對象,用于發送字符文本數據 (如 HTML, XML, JSON, plain text)。- 在使用
getWriter()
之前,應該先通過response.setContentType()
和/或response.setCharacterEncoding()
設置正確的字符編碼。
- 在使用
response.getOutputStream()
: 返回一個javax.servlet.ServletOutputStream
對象,用于發送二進制數據 (如圖片, PDF, ZIP 文件)。
重要: 你在一個響應中只能調用 getWriter()
或 getOutputStream()
一次。調用其中一個后,就不能再調用另一個了,否則會拋出 IllegalStateException
。
-
示例 (使用
PrintWriter
發送 HTML):response.setContentType("text/html; charset=UTF-8"); // response.setStatus(HttpServletResponse.SC_OK); // 默認是 200 OK,可以不顯式設置PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<meta charset=\"UTF-8\">"); out.println("<title>My Servlet Response</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello from Servlet!</h1>"); out.println("<p>This is a dynamic response.</p>"); out.println("</body>"); out.println("</html>"); // out.flush(); // 可選,容器通常會自動 flush // out.close(); // 可選,容器通常會自動關閉
-
示例 (使用
ServletOutputStream
發送圖片 - 假設imageData
是一個byte[]
):// byte[] imageData = ... ; // 從文件或數據庫加載圖片數據// response.setContentType("image/jpeg"); // response.setContentLength(imageData.length); // // response.setStatus(HttpServletResponse.SC_OK);// ServletOutputStream sos = response.getOutputStream(); // sos.write(imageData); // sos.flush(); // sos.close();
完整示例 (一個簡單的 Servlet):
package com.example;import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 1. 設置狀態碼 (默認是 200 OK,如果一切正常,可以不顯式設置)response.setStatus(HttpServletResponse.SC_OK);// 2. 設置響應頭response.setContentType("text/html; charset=UTF-8");response.setHeader("X-Server-Time", new Date().toString());// 3. 設置 CookieCookie visitCookie = new Cookie("lastVisit", String.valueOf(System.currentTimeMillis()));visitCookie.setMaxAge(60 * 60 * 24 * 7); // 7 daysvisitCookie.setPath(request.getContextPath() + "/");visitCookie.setHttpOnly(true);response.addCookie(visitCookie);// 4. 獲取 PrintWriter 并寫入響應體// (注意:一旦調用 getWriter() 或 getOutputStream(),響應頭就被認為是“已提交”,不能再修改狀態碼或頭信息)PrintWriter out = response.getWriter();out.println("<!DOCTYPE html>");out.println("<html>");out.println("<head>");out.println("<meta charset=\"UTF-8\">");out.println("<title>Servlet Response</title>");out.println("</head>");out.println("<body>");out.println("<h1>Hello, World from Servlet!</h1>");out.println("<p>Welcome! Your request was processed successfully.</p>");out.println("<p>Check your browser's developer tools for the 'X-Server-Time' header and the 'lastVisit' cookie.</p>");out.println("</body>");out.println("</html>");// 通常不需要顯式調用 out.close(),因為 Servlet 容器會在請求處理完成后自動關閉它。// 但如果是在 Filter 中或有特殊資源管理需求,可能需要。}
}
關鍵點總結:
- 順序很重要: 設置狀態碼、響應頭和 Cookie 必須在第一次調用
response.getWriter()
或response.getOutputStream()
之前完成,或者在響應被提交(flushed)之前完成。一旦響應體開始寫入,頭信息就不能再更改了。 getWriter()
vsgetOutputStream()
: 只能選擇一個,不能同時使用。- 字符編碼: 對于文本內容,務必設置正確的字符編碼(通常是 UTF-8)以避免亂碼問題。
- 容器管理: Servlet 容器負責在請求處理結束后刷新和關閉輸出流。
通過這些方法,HttpServletResponse
提供了全面的控制,使 Servlet 能夠構建并發送各種類型的 HTTP 響應給客戶端。