JSP HttpServletResponse 回應物件完整指南
HttpServletResponse 代表伺服器對客戶端的 HTTP 回應。JSP 隱含物件 response 即為其實例,提供設定狀態碼、標頭、Cookie、輸出流、編碼、緩衝區控制等功能。
HTTP 回應結構
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Set-Cookie: JSESSIONID=abc123; Path=/; HttpOnly
Cache-Control: no-cache
Content-Length: 1234
<!DOCTYPE html>
<html>...</html>
- 狀態行:版本、狀態碼、原因短語
- 回應標頭:Key-Value 配對
- 空行
- 回應主體:HTML、JSON、圖片、檔案等
核心 API 分類速查
1. 狀態碼與重導向
| 方法 | 說明 |
setStatus(int) | 設定狀態碼 (需在輸出前) |
sendRedirect(String) | 302 重導向 |
sendError(int) / sendError(int, String) | 發送錯誤頁面 |
2. 標頭操作
| 方法 | 說明 |
setHeader(name, value) | 設定單值標頭 (覆蓋) |
addHeader(name, value) | 新增標頭 (可多值) |
setDateHeader(name, ms) | 設定日期標頭 (毫秒數) |
setIntHeader(name, int) | 設定整數標頭 |
containsHeader(name) | 檢查標頭是否已設定 |
3. 內容型別與編碼
| 方法 | 說明 |
setContentType(type) | 設定 MIME 型別 + charset (如 text/html;charset=UTF-8) |
setCharacterEncoding(charset) | 設定字元編碼 (影響 getWriter) |
setContentLength(len) / setContentLengthLong(len) | 設定 Content-Length |
setLocale(Locale) | 設定語系 (自動產生 Content-Language) |
4. Cookie 管理
| 方法 | 說明 |
addCookie(Cookie) | 新增 Cookie 至 Set-Cookie 標頭 |
5. 輸出流與緩衝區
| 方法 | 說明 |
getWriter() | 取得字元輸出流 PrintWriter (文字內容) |
getOutputStream() | 取得位元組輸出流 ServletOutputStream (二進位檔案) |
flushBuffer() | 強制將緩衝區內容寫出客戶端 |
reset() | 清除緩衝區、標頭、狀態碼 (未提交前) |
resetBuffer() | 僅清除緩衝區內容 |
setBufferSize(int) | 設定緩衝區大小 (預設 8KB) |
isCommitted() | 回應是否已提交 (已寫出標頭) |
6. URL 重寫 (支援無 Cookie 環境)
| 方法 | 說明 |
encodeURL(String) | 編碼超連結 URL,附加 jsessionid |
encodeRedirectURL(String) | 編碼重導向 URL |
實作範例
1. 輸出 JSON (REST API 常用)
<%@ page contentType="application/json;charset=UTF-8" %>
<%
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
String json = "{\"status\":\"ok\",\"data\":{\"id\":1,\"name\":\"Demo\"}}";
out.print(json);
%>
2. 下載檔案 (附件模式)
<%@ page import="java.io.*, jakarta.servlet.http.*" %>
<%
String filePath = application.getRealPath("/WEB-INF/files/report.pdf");
File file = new File(filePath);
response.setContentType("application/pdf");
response.setContentLengthLong(file.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" +
java.net.URLEncoder.encode("報表.pdf", "UTF-8") + "\"");
try (FileInputStream fis = new FileInputStream(file);
ServletOutputStream sos = response.getOutputStream()) {
byte[] buf = new byte[4096];
int len;
while ((len = fis.read(buf)) > 0) sos.write(buf, 0, len);
}
%>
3. 圖片驗證碼輸出 (二進位流)
<%@ page import="java.awt.*, java.awt.image.*, javax.imageio.*, jakarta.servlet.*" %>
<%
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 0);
// 產生驗證碼圖片邏輯...
BufferedImage img = new BufferedImage(100, 40, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
// ... 繪製文字、干擾線 ...
g.dispose();
ImageIO.write(img, "PNG", response.getOutputStream());
%>
4. 自動刷新頁面 (Refresh 標頭)
<%
// 5 秒後重導向至首頁
response.setIntHeader("Refresh", 5);
// 或 5 秒後重導向指定 URL
// response.setHeader("Refresh", "5; url=" + request.getContextPath() + "/index.jsp");
%>
<html><body>
<h2>5 秒後自動跳轉...</h2>
</body></html>
5. 防快取設定 (登入後頁面必須)
<%
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
%>
JSP out 物件 vs response.getWriter()
out 是 JspWriter,支援緩衝區控制 (page 指令 buffer、autoFlush),例外為 IOException。
response.getWriter() 直接取得 PrintWriter,無 JSP 緩衝區包裝。
- 一般 JSP 使用
out 或 <%= %> 即可;Servlet 中才用 response.getWriter()。
常見錯誤與除錯
| 錯誤 | 原因 | 解決 |
IllegalStateException: getWriter() 已被呼叫 | 同一請求同時呼叫 getWriter() 與 getOutputStream() | 二選一,文字用 Writer,二進位用 OutputStream |
IllegalStateException: Cannot set header after response is committed | 已輸出內容導致標頭送出 | 設定標頭/狀態碼/重導向必須在任何 out.write()、<%@ page 輸出前 |
| 中文亂碼 | 未設定 charset | response.setContentType("text/html;charset=UTF-8") 或 page 指令 |
| 檔案下載檔名亂碼 | Content-Disposition 編碼 | RFC 5987 格式:filename*=UTF-8''%E5%A0%B1%E8%A1%A8.pdf |