JSP 的 errorPage 指令異常轉向錯誤頁的實現機制及應用

來源:互聯網
上載者:User

如有 index.jsp 頁,當出現後伺服器端異異常時要轉向到 errorPage.jsp,並在 errorPage.jsp 中把對應錯誤資訊顯示出來。我們需要在這兩個頁面分別加上指令 errorPage="errorPage.jsp" 和 isErrorPage="true"。

index.jsp

  1. <%@page errorPage="errorPage.jsp" %>  
  2.   
  3. <%   
  4.     throw new Exception("exception from jsp");   
  5. %>  

<%@page errorPage="errorPage.jsp" %></p><p><%<br /> throw new Exception("exception from jsp");<br />%>

errorPage.jsp

  1. <%@page isErrorPage="true" %>  
  2. <%   
  3.     out.println(exception);   
  4.        
  5.     //根據 Exception 類型及描述顯示可理解的資訊   
  6. %>  

<%@page isErrorPage="true" %><br /><%<br /> out.println(exception);</p><p> //根據 Exception 類型及描述顯示可理解的資訊<br />%>

errorPage.jsp 中必須加上 isErrorPage="true" 指令,才會存在內建變數 exception。直接存取 errorPage.jsp 沒有異常時,exception 為 null。

瀏覽器中用 URL http://localhost:8080/test/index.jsp 訪問,頁面輸出

java.lang.Exception: exception from index.jsp.

那實現機制是什麼呢?仍在常見的 Tomcat 容器中運行結果來分析

查看 Tomcat 編譯出的 index_jsp.java 進而追溯到(代碼片斷)

org.apache.jasper.runtime.PageContextImpl.doHandlePageException(Throwable t)() 中的部分代碼

  1. request.setAttribute("javax.servlet.jsp.jspException", t);   
  2. request.setAttribute("javax.servlet.error.request_uri",   
  3.         ((HttpServletRequest) request).getRequestURI());   
  4. forward(errorPageURL);   
  5.   
  6. Object newException = request.getAttribute("javax.servlet.error.exception");   
  7.   
  8. // t==null means the attribute was not set.   
  9. if( (newException!= null) && (newException==t) ) {   
  10.       request.removeAttribute("javax.servlet.error.exception");   
  11. }   
  12.   
  13. request.removeAttribute("javax.servlet.error.exception");   
  14. request.removeAttribute("javax.servlet.jsp.jspException");  

request.setAttribute("javax.servlet.jsp.jspException", t);<br /> request.setAttribute("javax.servlet.error.request_uri",<br /> ((HttpServletRequest) request).getRequestURI());<br /> forward(errorPageURL);</p><p> Object newException = request.getAttribute("javax.servlet.error.exception");</p><p> // t==null means the attribute was not set.<br /> if( (newException!= null) && (newException==t) ) {<br /> request.removeAttribute("javax.servlet.error.exception");<br /> }</p><p> request.removeAttribute("javax.servlet.error.exception");<br /> request.removeAttribute("javax.servlet.jsp.jspException");

同樣要翻看 Tomcat 編譯出的 errorPage_jsp.java 可看到(代碼片斷)

Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); // JSP 中

org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request) 中的部分代碼

  1. Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION);   
  2. if (error == null) {   
  3.     error = (Throwable) request.getAttribute(JSP_EXCEPTION);   
  4. (error != null) {   
  5.         request.setAttribute(SERVLET_EXCEPTION, error);  

Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION);<br /> if (error == null) {<br /> error = (Throwable) request.getAttribute(JSP_EXCEPTION);<br /> if (error != null) {<br /> request.setAttribute(SERVLET_EXCEPTION, error);

 

最終都是以 SERVLET_EXCEPTION 把異常設定到 request 中

在 JspRuntimeLibrary 定義了這兩個常量字串

private static final String SERVLET_EXCEPTION = "javax.servlet.error.exception";
private static final String JSP_EXCEPTION = "javax.servlet.jsp.jspException";

如果要在自己的代碼中,如 Servlet、Filter、Struts 的 RequestProcessor 或 Struts Action 中出現異常也能轉向到 errorPage.jsp,並能複用原來的 errorPage.jsp 中顯示錯誤資訊的代碼,該如何應用上面的分析成果呢?

下面以 Struts Action 為例來說明,應用於其他地方可借鑒。為什麼用了 Struts 卻不用 Struts 提供的異常處理模型呢?也是無奈的,維護的舊系統,框上了 Struts,其他各處只能慢慢來換。

只要在 Struts Action 中的 execute() 方法中寫上

  1. Throwable t = new Exception("exception from Struts Action.");   
  2. request.setAttribute("javax.servlet.error.jspException", t);   
  3.   
  4. //或者在 struts-config.xml 中配置一個全域錯誤頁   
  5. return new ActionForward("/errorPage.jsp");  

Throwable t = new Exception("exception from Struts Action.");<br /> request.setAttribute("javax.servlet.error.jspException", t);</p><p> //或者在 struts-config.xml 中配置一個全域錯誤頁<br /> return new ActionForward("/errorPage.jsp");

進一步深入你可以自訂一個 Struts 的異常處理類來做這個事情。
這時候還需要自已在 errorPage.jsp 的最後一行加上 java 代碼:

request.removeAttribute("javax.servlet.error.exception");

去除 request 中的異常屬性,不然沒法用 errorPage.jsp 顯示錯誤,而代之為的是那個常見的

HTTP Status 500 -

description The server encountered an internal error () that prevented it from fulfilling this request.

這時候瀏覽器中通過 URL http://localhost:8080/test/test.do 訪問,頁面輸出

java.lang.Exception: exception from Struts Action.

最後嘗試把這個項目發布到 Websphere Application Server (WAS) 5.1 下,訪問 http://localhost:9080/test/test.do,頁面輸出 null,沒取到異常!

沒什麼好辦法,還是反編譯 WAS 產生的 JSP 代碼中,發現到 WAS 5.1 的 PageContext 的實作類別也是 org.apache.jasper.runtime.PageContextImpl,在 WAS_HOME/lib/webcontainer.jar 包中。在這個 PageContextImpl 類中也是設定

request.setAttribute("javax.servlet.jsp.jspException", t);

但是WAS 5.1 下 errorPage.jsp 直接通過 request 來取異常:

throwable = (Throwable)httpservletrequest.getAttribute("javax.servlet.jsp.jspException");

不再理會 request 中的 javax.servlet.error.exception 屬性值的。

因此只要注意一點,在 Tomcat 中,Action 裡既可以設定

request.setAttribute("javax.servlet.error.exception", t);

也可以是

request.setAttribute("javax.servlet.jsp.jspException", t);

當然在 WAS 5.1 下的 errorPage.jsp 中就不需要

request.removeAttribute("javax.servlet.error.exception");

那要不要用

request.removeAttribute("javax.servlet.jsp.jspException");

移除 request 中的 javax.servlet.jsp.jspException 屬性呢?也用不著啦。

Tomcat 下和 WAS 下的 jsp 頁面的主要差別是在它們的基類不同,Tomcat 下的 JSP 頁是繼承自 org.apache.jasper.runtime.HttpJspBase,而 WAS 5.1 下的 JSP 頁是繼承自 com.ibm.ws.webcontainer.jsp.runtime.HttpJspBase。

考慮在能相容兩種平台的做法應該是,在 Action 中統一用

request.setAttribute("javax.servlet.jsp.jspException", t);

設定異常,然後在 errorPage.jsp 補上一行

request.removeAttribute("javax.servlet.error.exception");

就 OK 啦。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.