JSF 2.0自定义异常处理程序在handleNavigation上抛出IllegalStateException



我为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响应的第一部分(包括报头)已经被发送到客户端。这是一个没有退路的时刻。您不能从客户端取回已发送的字节。

当写入的内容超过缓冲区大小时,响应通常会自动提交,缓冲区大小默认为2KB,这取决于servletcontainer和Facelets的配置。HTML <head>平均占用1~2KB。所以变化很大,在JSF开始渲染<body>之前,响应就已经提交了,或者只是其中的一小部分。

你的特殊的情况下,然而,还有一个原因:当你收到多个未处理的异常时,那么你也会遇到麻烦,因为你没有在导航后中止while循环,而是继续处理下一个异常。您不能为单个请求返回多个响应(错误页面)。您应该收集所有异常并只导航一次,或者在第一个异常之后终止循环。

在任何情况下,处理在渲染响应期间抛出的异常只有在响应没有(自动)提交的情况下才有可能。您可以尝试几种方法来防止响应过早地自动提交:

  1. 将Facelets缓冲区大小设置为最大的HTML响应大小。例如64 kb:

    <context-param>
        <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
        <param-value>65535</param-value><!-- 64KB -->
    </context-param>
    
  2. 在呈现视图之前执行异常敏感的业务作业(即不要在GET请求期间构造的bean的(post)构造函数中执行):

    <f:event type="preRenderView" listener="#{bean.init}" />
    

一般来说,要处理JSF中的异常,您可能会发现OmniFaces FullAjaxExceptionHandler很有帮助。你可以在这里找到源代码。

参见:

  • 在JSF 2.1中@PostConstruct抛出的异常导致IllegalStateException
  • 在web.xml中定义的错误页面嵌入到部分呈现的JSF页面

相关内容

  • 没有找到相关文章

最新更新