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

导读:本篇文章讲解 解决java.lang.IllegalStateException: Cannot call sendError() after the response has been committed异常,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

概述

相信大家自己在用spring boot写restful风格的接口时特别是写文件下载或文件导出时会碰到java.lang.IllegalStateException: Cannot call sendError() after the response has been committed这样的bug,很多人可能一脸困惑,就好奇为什么我文件都已经可以正常导出了,为什么在日志中还是会出现这样的报错呢?到底是什么原因导致的呢?

错误日志

在这里插入图片描述

错误分析

截图第一部分中可以看到日志中打印出了java.lang.IllegalStateException: Cannot call sendError() after the response has been committed这样的报错,从字面上理解抛出的是非法状态的异常,具体原因为提交响应后无法调用sendError()这个方法,从截图第二部分中可以看出的是http媒体类型不可接受的异常,具体原因为找不到可接受的表示。这两个报错有着一定的关联,应该是响应在被提交后无法调用sendError()这个方法,所以才进一步导致了找不到可接受的表示这个报错!
那么问题来了,该怎么解决呢?看了网上的一些经验并结合了自己代码排查后终于发现自己在导出文件接口中存在两个输出的动作,这两个return语句都是与输出有着紧密的关系,原来我在使用完第一个输出时之后把输出流给关闭掉了,所以也就导致了真正执行第二个输出时出现了response被提交之后不能发送错误请求的bug。具体代码如下所示:
在这里插入图片描述
第一个使用的是alibaba的EasyExcel框架,发现在使用完outputStream后把流关闭了。
大致代码如下:
com.alibaba.excel.write.builder.ExcelWriterSheetBuilder#doWrite

    public void doWrite(List data) {
        if (excelWriter == null) {
            throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method");
        }
        excelWriter.write(data, build());
        excelWriter.finish();
    }

excelWrite.finish()方法最后把流关闭了,具体的代码大家可以跟下,下面贴出核心代码。

  try {
            if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) {
                writeWorkbookHolder.getOutputStream().close();
            }
        } catch (Throwable t) {
            throwable = t;
        }
        if (writeExcel && !isOutputStreamEncrypt) {
            try {
                doFileEncrypt07();
            } catch (Throwable t) {
                throwable = t;
            }
        }
        try {
            if (writeWorkbookHolder.getTempTemplateInputStream() != null) {
                writeWorkbookHolder.getTempTemplateInputStream().close();
            }
        } catch (Throwable t) {
            throwable = t;
        }

我们看到第二个输出是输出一个json对象(因为我在类的头部使用了@RestController注解),因为第一个输出是流的方式输出,并且输出成功后又把输出流给关闭了,所以自然就对第二个输出造成了影响!那么怎么办呢?很简单,直接把第二个的 return ResultDTO.buildForSuccess();这段代码改为return null就不会报如上这两个报错了。

修改方法

最后一个输出改成return null,不在使用关闭的流即可。
在这里插入图片描述

参考

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99912.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!