我为 JSF 编写了一个自定义异常处理程序来记录异常并导航到要向用户显示的错误页面。不幸的是,在 Handler 中调用“handleNavigation”时,我收到 IllegalStateException“无法在提交响应后调用 sendRedirect()”。任何想法,我做错了什么?
我的处理程序:
public class MyExceptionHandler extends ExceptionHandlerWrapper {
private Logger log = ...;
public ExceptionHandler wrappedHandler = null;
public MyExceptionHandler (ExceptionHandler wrappedHandler) {
this.wrappedHandler = wrappedHandler;
}
@Override
public ExceptionHandler getWrapped() {
return wrappedHandler;
}
@Override
public void handle() throws FacesException {
Iterator<ExceptionQueuedEvent> iter = null;
ExceptionQueuedEvent event = null;
ExceptionQueuedEventContext eventContext = null;
FacesContext facesContext = null;
iter = getUnhandledExceptionQueuedEvents().iterator();
while (iter.hasNext()) {
try {
event = iter.next();
eventContext = (ExceptionQueuedEventContext) event.getSource();
log.error("JSF Exception aufgetreten", eventContext.getException());
facesContext = FacesContext.getCurrentInstance();
// !!!!!!!! Exception occurs here !!!!!!!!!!!
facesContext
.getApplication()
.getNavigationHandler()
.handleNavigation(facesContext, null, "error");
facesContext.renderResponse();
} catch (RuntimeException ex) {
throw ex; // just to set break point
} finally {
iter.remove();
}
}
getWrapped().handle();
}
}
faces-config.xml 中的导航定义
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>error</from-outcome>
<to-view-id>/faces/error.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
最佳答案
正在处理的异常显然是在渲染响应阶段抛出的,此时 HTTP 响应已经提交。提交的响应意味着 HTTP 响应的第一部分(包括 header )已经发送到客户端。这是一条不归路。您无法从客户端取回已发送的字节。
当写入的内容超过缓冲区大小时,通常会自动提交响应,缓冲区大小通常默认为 ~2KB,具体取决于 servletcontainer 和 Facelets 配置。平均 HTML <head>
已经占用1~2KB。所以变化很大,在 JSF 开始呈现 <body>
之前已经提交了响应。或者只是其中的一小部分。
在您的特定情况下还有一个原因:当您收到不止一个未处理的异常时,您也会遇到麻烦,因为您没有中止 while
导航后循环,但继续处理下一个异常。您不能对单个请求返回多个响应(错误页面)。您应该收集所有异常并仅导航一次,或者在第一个异常之后中止循环。
在任何情况下,处理渲染响应期间抛出的异常只有在响应未(自动)提交时才有可能。您可以尝试多种方法来防止响应过早自动提交:
将 Facelets 缓冲区大小设置为最大 HTML 响应的大小。例如。 64KB:
<context-param> <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name> <param-value>65535</param-value><!-- 64KB --> </context-param>
在呈现 View 之前执行异常敏感的业务作业(即不要在 GET 请求期间构造的 bean 的(后)构造函数中执行此操作):
<f:event type="preRenderView" listener="#{bean.init}" />
关于一般 JSF 中的异常处理,您可能会发现 OmniFaces FullAjaxExceptionHandler
有帮助。你可以找到它的源代码 here .
另见:
关于JSF 2.0 自定义异常处理程序在 handleNavigation 上抛出 IllegalStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15610974/