当前位置:   article > 正文

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

java.lang.illegalstateexception: cannot call senderror() after the response

概述

相信大家自己在用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();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

修改方法

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

参考

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/66302
推荐阅读
相关标签
  

闽ICP备14008679号