我为JSF编写了一个自定义异常处理程序来记录异常并导航到一个错误页面以显示给用户。不幸的是,我得到了一个IllegalStateException“在提交响应之后无法调用sendRedirect()”在Handler中调用“handleNavigation”时。任何想法,我做错了什么?
我的处理程序:
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>
答案 0 :(得分:2)
在呈现响应阶段,当HTTP响应已经提交时,显然已经抛出了正在处理的异常。提交的响应意味着HTTP响应的第一部分(包括标头)已经发送到客户端。这是一个不归路。您无法从客户端返回已发送的字节。
当写入的内容超过缓冲区大小时,通常会自动提交响应,默认情况下通常为~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>
在呈现视图之前执行异常敏感的业务作业(即,不要在GET请求期间构造的bean的(post)构造函数中执行此操作):
<f:event type="preRenderView" listener="#{bean.init}" />
对于JSF中的异常处理,您可能会发现OmniFaces FullAjaxExceptionHandler
有帮助。您可以找到其源代码here。