JSP HTTP 狀態碼與錯誤處理
HTTP 狀態碼告知客戶端請求處理結果。JSP/Servlet 可透過 HttpServletResponse 設定狀態碼、重導向、發送錯誤頁面。
常見狀態碼分類
| 範圍 | 類別 | 常見代碼 | 含義 |
| 1xx | 資訊回應 | 100 Continue | 繼續傳送請求主體 |
| 2xx | 成功 | 200 OK, 201 Created, 204 No Content | 請求成功處理 |
| 3xx | 重導向 | 301 Moved Permanently, 302 Found, 304 Not Modified | 需進一步動作完成請求 |
| 4xx | 客戶端錯誤 | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed | 請求語法錯誤或無權限 |
| 5xx | 伺服器錯誤 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable | 伺服器處理失敗 |
HttpServletResponse 設定狀態碼方法
| 方法 | 說明 |
setStatus(int code) | 設定狀態碼,需在輸出內容前呼叫 |
sendRedirect(String url) | 發送 302 + Location 標頭,瀏覽器自動跳轉 |
sendError(int code) | 發送錯誤狀態碼,並由容器顯示預設/配置錯誤頁 |
sendError(int code, String msg) | 發送錯誤碼與訊息,容器生成錯誤頁包含訊息 |
setHeader("Location", url) + setStatus(301) | 手動控制重導向行為 (如 301 永久) |
實作範例
1. 發送 404 並顯示自訂訊息
<%@ page contentType="text/html;charset=UTF-8" %>
<%
// 找不到資源時
response.sendError(HttpServletResponse.SC_NOT_FOUND, "請求的商品不存在 (ID: " + request.getParameter("id") + ")");
%>
2. 手動設定 301 永久重導向 (SEO 友善)
<%
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301
response.setHeader("Location", "https://newdomain.com/new-path");
%>
3. REST API 回傳 201 Created + Location
<%@ page import="jakarta.servlet.http.HttpServletResponse" %>
<%
// 新增資源成功
long newId = 12345;
response.setStatus(HttpServletResponse.SC_CREATED); // 201
response.setHeader("Location", request.getRequestURL() + "/" + newId);
response.setContentType("application/json");
out.print("{\"id\":" + newId + ",\"message\":\"created\"}");
%>
4. 401 Unauthorized 觸發瀏覽器驗證對話框
<%
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
response.setHeader("WWW-Authenticate", "Basic realm=\"Admin Area\"");
out.println("需要認證");
%>
web.xml 宣告式錯誤頁面配置
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/exception.jsp</location>
</error-page>
錯誤頁面取得例外資訊 (error/exception.jsp)
<%@ page isErrorPage="true" contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>系統錯誤</title></head>
<body>
<h1>系統發生錯誤</h1>
<p>狀態碼:<%= response.getStatus() %></p>
<p>錯誤訊息:<%= exception.getMessage() %></p>
<% if (exception != null) { %>
<pre><%= exception.getClass().getName() %>
<%
for (StackTraceElement ste : exception.getStackTrace()) {
out.println("\tat " + ste);
}
%>
</pre>
<% } %>
<p><a href="<%= request.getContextPath() %>/index.jsp">返回首頁</a></p>
</body></html>
Servlet 3.0+ 程式化錯誤頁面註冊
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
@Override public void init() {
ServletContext ctx = getServletContext();
ctx.setErrorPage(Exception.class, "/error/exception.jsp");
ctx.addErrorPage(404, "/error/404.jsp");
}
}
最佳實踐
- 統一錯誤處理:配置 web.xml 錯誤頁,避免堆疊追蹤洩露給使用者。
- REST API 回傳 JSON 錯誤:
{"error":"NOT_FOUND","message":"...","timestamp":...},不回傳 HTML。
- 記錄完整堆疊:伺服器端 Log 記錄完整例外,使用者端僅顯示友善訊息。
- 監控告警:5xx 錯誤率超過閾值觸發告警 (ELK、Prometheus、Datadog 等)。
- 自訂錯誤頁面品牌化:保持網站風格,提供搜尋、聯繫客服、返回首頁連結。