Filter 規範說「不能直接響應,只能修改請求/響應對象」,但 Struts2 明顯能做 response.sendRedirect()、轉發、直接輸出內容。它是怎麼做到的?
Struts2 的核心 StrutsPrepareAndExecuteFilter **並不直接生成最終響應**,而是:
doFilter() 入口。"success"),由 Result 實現類處理:
DispatcherResult:request.getRequestDispatcher("/xxx.jsp").forward(req, resp) → **轉發給 Servlet/JSP**。ServletRedirectResult:response.sendRedirect(url) → **發送 302 重定向**。StreamResult、PlainTextResult 等:**直接向 response.getOutputStream() 寫入數據**。chain.doFilter() 將控制權交還容器,由容器處理轉發/重定向後的後續流程。Struts2 Filter **不調用** response.getWriter().write(...) 來生成最終 HTML。它**準備好數據模型、選擇視圖路徑**,然後**通過標準 Servlet API(forward/redirect/stream)委派給容器或其他 Servlet 執行最終渲染**。
HTTP Request
│
▼
[StrutsPrepareAndExecuteFilter.doFilter()]
│
├─► ActionMapping/ActionProxy 查找 Action
│
├─► Interceptor 鏈執行 (驗證、文件上傳、參數注入...)
│
├─► Action.execute() 返回 "success"
│
├─► Result 類型判斷
│ ├─ dispatcher → request.forward("/view.jsp") → [容器處理 JSP → Servlet → HTML]
│ ├─ redirect → response.sendRedirect("/url") → [瀏覽器發新請求]
│ └─ stream/json → response.getOutputStream().write(bytes) → [直接輸出]
│
▼
chain.doFilter(req, resp) // 放行,容器接管後續
│
▼
HTTP Response
在 Action 中注入 HttpServletResponse response 並調用 response.getWriter().write("hello"),**技術上可行**,但會導致:
IllegalStateException: Cannot forward after response has been committed。正確做法:Action 返回結果名,配置 struts.xml 對應 Result 類型,由框架統一處理響應提交。
Struts2 不是「違規操作 Filter」,而是**標準的 Filter + Servlet 協作模式**的教科書級實現。