java.lang.IllegalStateException: Cannot call sendError() after the response has been committed解决思路

 其实就是在web项目中添加了一个过滤器,作为平台的开关,实现代码如下:

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        if (!httpRequest.getServletPath().equals("/switch/lock")
                && !httpRequest.getServletPath().equals("/switch/unlock")) {
            
            logger.error("ServletPath: " + httpRequest.getServletPath());

            boolean switcherLock = false;
            try {
                switcherLock = SwitchServiceImpl.getInstance().getSwitchLock();
                logger.error("后台当前锁状态是: " + switcherLock);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (switcherLock) {
                httpResponse.sendError(403);
            }
        }            
        chain.doFilter(request, response);

    }

web.xml
        
    <filter>
        <filter-name>switchfilter</filter-name>
        <filter-class>com.jieve.filter.SwitchFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>switchfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <error-page>
        <error-code>404</error-code>
        <location>/views/common/404.html</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/views/common/500.html</location>
    </error-page>
    <error-page>
        <error-code>403</error-code>
        <location>/views/common/403.html</location>
    </error-page>



说下这个问题出现的原因,报错内容`Cannot call sendError() after the response has been committed`从字面上可以看出是因为response已经提交过了,所以不能调用sendError()方法。


首先说下,过滤器是链式结构的,就是说配了多个过滤器的话,通过`chain.doFilter(request, response);`可以依次链式调用,如果说出现response多次提交的话,应该就是其中一个过滤器response提交之后,再通过调用`chain.doFilter(request, response);`方法将response传递到下一个过滤器;或者在一个过滤器内多次提交response。

排除第二种情况出现的可能性,看下sendError()方法实现:

    public void sendError(int sc) throws IOException {
        this._getHttpServletResponse().sendError(sc);
    }

方法的官方注释如下:

    sendError(int sc):使用指定的状态码并清空缓冲,发送一个错误响应至客户端。如果响应已经被提交,
    这个方法会抛出IllegalStateException。使用这个方法后,响应则应该被认为已被提交,且不应该再被进行写操作了。

可以看出是在`httpResponse.sendError(403);`执行提交了response,所以`chain.doFilter(request, response);`传递到下个过滤器的response不可再被提交,即报错`java.lang.IllegalStateException: Cannot call sendError() after the response has been committed`

解决思路是保证在任何情况下都保证response单次提交,修改代码如下:

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        if (!httpRequest.getServletPath().equals("/switch/lock")
                && !httpRequest.getServletPath().equals("/switch/unlock")) {
            
            logger.error("ServletPath: " + httpRequest.getServletPath());

            boolean switcherLock = false;
            try {
                switcherLock = SwitchServiceImpl.getInstance().getSwitchLock();
                logger.error("后台当前锁状态是: " + switcherLock);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (switcherLock) {
                httpResponse.sendError(403);
            }else {
                chain.doFilter(request, response);
            }
        }else {
            
            chain.doFilter(request, response);
        }

    }

细化处理错误的分支,部署,测试,问题解决。
阅读更多
个人分类: Java
上一篇jsoup处理html标签分享
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭