Springboot 文件下载异常 IOException: UT010029: Stream is closed

今天在测试项目过程中,发现下载文件时日志中出现了一个异常。虽然异常了,但是文件还是可以正常下载的。

 文件下载代码如下

@RequestMapping(value = "/info", method = RequestMethod.GET)
    public HMResponse info(Long id, Long customerId, HttpServletResponse response) {
        String info = requestInfoService.getInfo(id, customerId);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + System.currentTimeMillis() + ".txt");
            response.setContentType("application/octet-stream");
            out.write(info.getBytes());
        } catch (Exception e) {
            logger.error("下载报文", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                logger.error("", e);
            }
        }
        return HMResponse.getInstance();
    }

异常信息如下

2022-11-10 14:15:43.363 ERROR [501aad039274c7a0 ◊ 501aad039274c7a0] [XNIO-3 task-6] com.platform.common.configuration.exceptio
n.AbstractGeneralGlobalExceptionHandler.printErrorLog @38 :-> method:GET, RequestURL:http://111.106.31.81:8080/data-platform/reque
stInfo/info?id=10382&customerId=1001, java.io.IOException: UT010029: Stream is closed
    at io.undertow.servlet.spec.ServletOutputStreamImpl.write(ServletOutputStreamImpl.java:136) ~[undertow-servlet-1.4.20.Fin
al.jar!/:1.4.20.Final]
    at org.springframework.cloud.sleuth.instrument.web.TraceServletOutputStream.write(TraceServletOutputStream.java:120) ~[sp
ring-cloud-sleuth-core-1.2.5.RELEASE.jar!/:1.2.5.RELEASE]
    at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:167) ~[?:1.8.0_60]
    at com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter.writeInternal(FastJsonHttpMessageConverter.java:337) 
~[fastjson-1.2.83.jar!/:?]
    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227) ~[spring-
web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter.write(FastJsonHttpMessageConverter.java:246) ~[fastjs
on-1.2.83.jar!/:?]
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverte
rs(AbstractMessageConverterMethodProcessor.java:231) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResp
onseBodyMethodProcessor.java:174) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnV
alueHandlerComposite.java:81) ~[spring-web-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHa
ndlerMethod.java:113) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingH
andlerAdapter.java:827) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandle
rAdapter.java:738) ~[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~
[spring-webmvc-4.3.11.RELEASE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.11.RELEASE
.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.11.RELEASE.
jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.11.RELEA
SE.jar!/:4.3.11.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.11.RELEASE.jar!/:
4.3.11.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687) [javax.servlet-api-3.1.0.jar!/:3.1.0]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.11.RELEASE.jar!
/:4.3.11.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [javax.servlet-api-3.1.0.jar!/:3.1.0]
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.4.20.Final.jar!/
:1.4.20.Final]
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) [undertow-servlet-1.4.20.F
inal.jar!/:1.4.20.Final]
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.jav
a:55) [spring-boot-1.5.7.RELEASE.jar!/:1.5.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.11.RELEASE
.jar!/:4.3.11.RELEASE]
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-1.4.20.Final.jar!/:1.4.20.Fin
al]
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-1.4.20.F
inal.jar!/:1.4.20.Final]
    at com.github.xiaoymin.swaggerbootstrapui.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:84) [swagg
er-bootstrap-ui-1.9.6.jar!/:?]
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-1.4.20.Final.jar!/:1.4.20.Fin
al]
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) [undertow-servlet-1.4.20.F
inal.jar!/:1.4.20.Final]
    at com.github.xiaoymin.swaggerbootstrapui.filter.ProductionSecurityFilter.doFilter(ProductionSecurityFilter.java:53) [swa
gger-bootstrap-ui-1.9.6.jar!/:?]
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) [undertow-servlet-1.4.20.Final.jar!/:1.4.20.Fin
al]

 上网查了一下解决方案,有部分的解决方案是,修改全局的异常捕获处理器注解。个人认为这种方式不是从根本上解决问题,我也没有尝试这个方案。因为没有全局异常处理器。该异常也不会存在。

@ExceptionHandler(Exception.class) 改成 @ExceptionHandler(BindException.class)

 

与是参考了网上的另一个解决方案

从异常日志和 Debug 跟踪,发现异常是从 Spring 框架层抛出的,下载业务逻辑并未出现异常,就分析猜测:问题可能出在 out.close () 上,把流关闭注释掉后就正常了。

 后面进一步测试发现,如果要保留关闭流的习惯,下载方法就不要有任何返回值,这样也是可以的。

总结:

1、使用 Spring框架时,在我们的业务代码中处理完业务逻辑后,不要对 HttpServletResponse 对象的 ServletOutputStream 做流关闭处理;

2、使用 Spring 框架时,对于下载文件的方法请不要有任何返回值,因为我们写完业务逻辑后 Spring 框架层还会做一些额外的工作(可能会用到 ServletOutputStream 对象,所以不能关闭)。

 

最后修改后的代码

 @RequestMapping(value = "/info", method = RequestMethod.GET)
    public HMResponse info(Long id, Long customerId, HttpServletResponse response) {
        String info = requestInfoService.getInfo(id, customerId);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + System.currentTimeMillis() + ".txt");
            response.setContentType("application/octet-stream");
            out.write(info.getBytes());
        } catch (Exception e) {
            log.error("下载报文", e);
        }
        return HMResponse.getInstance();
    }

 

  

 

posted @ 2022-11-10 17:42  蜗牛学编程  阅读(2797)  评论(0编辑  收藏  举报