简体   繁体   English

我得到一个异常:java.lang.IllegalStateException:已经为此响应调用了getOutputStream()

[英]I am getting an exception: java.lang.IllegalStateException: getOutputStream() has already been called for this response

I want to write code to download a file which is persisted in my system 我想编写代码来下载一个存储在我系统中的文件

Here is my code: 这是我的代码:

In a controller class I have following mapping 在控制器类中,我有以下映射

@RequestMapping(value = "/processFile", method = RequestMethod.POST)
    public @ResponseBody ModelAndView downloadFileProcess(
            @RequestParam("file") File originalFile,
            @RequestParam("action") String action, HttpServletResponse response) {

        ModelAndView model = new ModelAndView();
        model.setViewName("error");
        System.out.println("");
        System.out.println("Action: "+action);
        model.addObject("message", "Action:" + action);
        try {
            utility.downloadFile(originalFile, response);
            message = "The file was downloaded successfully";

        } catch (IOException e) {
            e.printStackTrace();
            message = "The process failed due to following reason: "
                    + e.getMessage();
        } catch (Exception e) {
            e.printStackTrace();
            message = "The process failed due to following reason: "
                    + e.getMessage();
        }
        model.setViewName("success");
        model.addObject("message", message);
        return model;
    }

The method in the utility class is below: 实用程序类中的方法如下:

public void downloadFile(File originalFile, HttpServletResponse response)
            throws FileNotFoundException, IOException {

        response.setHeader("Content-Disposition", "attachment; filename="
                + originalFile.getName());
        IOUtils.copy(
                new FileInputStream(new File(String.valueOf(originalFile))),
                response.getOutputStream());
        response.flushBuffer();

    }

As I want to download the file, I have to use response.getoutputstream() . 因为我想下载文件,我必须使用response.getoutputstream()

But I am getting the following exception: 但我得到以下异常:

java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
    at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:482)
    at org.springframework.web.servlet.view.RedirectView.sendRedirect(RedirectView.java:548)
    at org.springframework.web.servlet.view.RedirectView.renderMergedOutputModel(RedirectView.java:279)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

2015-05-31 12:42:07.547 ERROR 15009 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet dispatcherServlet threw exception

java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:678)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:213)
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:104)
    at org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView.render(ErrorMvcAutoConfiguration.java:187)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604)
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:467)
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:342)
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:434)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:205)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

2015-05-31 12:42:07.551 ERROR 15009 --- [nio-8080-exec-4] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604)
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:467)
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:342)
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:434)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:205)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:678)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:213)
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:104)
    at org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView.render(ErrorMvcAutoConfiguration.java:187)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    ... 27 common frames omitted

You want a single request to have two different responses: 您希望单个请求有两个不同的响应:

  • one which contains the bytes of the downloaded file as its body 一个包含下载文件的字节作为其主体
  • one which contains an HTML page generated by the success view 包含由成功视图生成的HTML页面的一个

That does not make sense. 那没有意义。 It can only be one or the other. 它只能是一个或另一个。 If you want the request to download a file, then you shouldn't return a ModelAndView. 如果您希望请求下载文件,则不应返回ModelAndView。 The method should return void. 该方法应返回void。

Also, the method should not be annotated with @ResponseBody . 此外,该方法不应使用@ResponseBody进行注释。

AFAIK, the way download sites generate a success page and a file download at the same time simply consists in responding with a HTML page containing an iframe, and have the iframe pointing at the URL for the actual file download. AFAIK,下载网站同时生成成功页面和文件下载的方式只是响应包含iframe的HTML页面,并让iframe指向实际文件下载的URL。

  1. HttpServletResponse.getOutputStream() HttpServletResponse.getOutputStream()

    • Used to write binary data to the client. 用于将二进制数据写入客户端。
    • Data written to the client is not encoded. 写入客户端的数据未编码。
    • Once flush() is called, data is flushed to the client. 调用flush()后,数据将刷新到客户端。
    • IllegalStateException will be thrown if the getWriter() method has been called on this response object. 如果在此响应对象上调用了getWriter()方法,则抛出IllegalStateException
  2. HttpServletResponse.getWriter() HttpServletResponse.getWriter()

    • Returns a PrintWriter object which can be used to write character text (non-binary) data to the client. 返回PrintWriter对象,该对象可用于将字符文本(非二进制)数据写入客户端。
    • Data sent to the client is encoded either using default encoding scheme or user provided. 发送到客户端的数据使用默认编码方案或用户提供的方式进行编码。
    • Once flush() is called, data is flushed to the client. 调用flush()后,数据将刷新到客户端。
    • IllegalStateException will be thrown if the getOutputStream() method has already been called for this response object 如果已为此响应对象调用了getOutputStream()方法,则抛出IllegalStateException

One key usage difference between 2 is that getOutputStream() is for sending binary data to client and getWriter() is for sending encoded text data. 2之间的一个关键用法区别是getOutputStream()用于将二进制数据发送到客户端,getWriter()用于发送编码的文本数据。

Bottom line: Either of the above 2 methods should be used to flush data to client, and not both, and developer has to make sure that it is properly handled, specially when doing things in a non-servlet class. 结论:上述两种方法中的任何一种都应该用于将数据刷新到客户端,而不是两者,并且开发人员必须确保正确处理它,特别是在非servlet类中执行操作时。

This is the problem with PrintWriter.getWriter() and HttpServletResponse.getOutputStream() both of which try to flush the data to client. 这是PrintWriter.getWriter()HttpServletResponse.getOutputStream()的问题,两者都试图将数据刷新到客户端。

You are already using response.getOutputStream() and response.flushBuffer() , which means that you are trying to flush the content to client, and then finally when your downloadFileProcess() is returning, Springs is also trying to flush the content using PrintWriter.getWriter() so you get 您已经在使用response.getOutputStream()response.flushBuffer() ,这意味着您正在尝试将内容刷新到客户端,最后当您的downloadFileProcess()返回时,Springs也尝试使用PrintWriter.getWriter()刷新内容PrintWriter.getWriter()所以你得到

java.lang.IllegalStateException: getOutputStream() has already been called for this response java.lang.IllegalStateException:已为此响应调用了getOutputStream()

Use code as below to send some content to client without making your method as void, and that should help. 使用下面的代码将一些内容发送到客户端,而不会使您的方法无效,这应该有所帮助。

String content = null;
IOUtils.copy(new FileInputStream(new File(String.valueOf(originalFile))), content );
PrintWriter out = response.getWriter();
out.println(content);

On a side note, why you are doing model.setViewName("error"); 另外,为什么要做model.setViewName("error"); and model.addObject("message", "Action:" + action); model.addObject("message", "Action:" + action); in the start? 在一开始? I think either you should not have it because you are overriding in the end or they are better fitted in the CATCH blocks. 我认为你不应该拥有它,因为你最终会压倒一切,或者它们更适合CATCH区块。

I solved the problem that way: 我这样解决了问题:

ApplicationContext context = new FileSystemXmlApplicationContext();
Resource resource = context.getResource("file:" + exFile.getPath());

File file = new File(exFile.getPath());
try {
   response.setHeader("Content-Disposition", "attachment; filename="                 + file.getName());
   InputStream is = resource.getInputStream();
   IOUtils.copy(is, response.getOutputStream());

} catch (IOException e) {
    e.printStackTrace();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我正在获取java.lang.IllegalStateException:此响应已调用getOutputStream()异常 - I m getting java.lang.IllegalStateException: getOutputStream() has already been called for this response Exception java.lang.IllegalStateException:已经为此响应调用了 getOutputStream() - java.lang.IllegalStateException: getOutputStream() has already been called for this response java.lang.IllegalStateException:已为此响应调用了getOutputStream() - java.lang.IllegalStateException: getOutputStream() has already been called for this response 获取Exception-java.lang.IllegalStateException:此响应已调用getOutputStream() - Getting Exception-java.lang.IllegalStateException: getOutputStream() has already been called for this response 原因:java.lang.IllegalStateException:此响应已经调用了getOutputStream()。 - Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response org.apache.jasper.JasperException:java.lang.IllegalStateException:此响应已调用getOutputStream() - org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response Spring Boot Web应用程序:引发java.lang.IllegalStateException:此响应已调用getOutputStream() - Spring Boot Web Application: throwing java.lang.IllegalStateException: getOutputStream() has already been called for this response REST-java.lang.IllegalStateException:此响应已调用getOutputStream() - REST - java.lang.IllegalStateException: getOutputStream() has already been called for this response Spring MVC: java.lang.IllegalStateException: getOutputStream() 已经被这个响应调用 - Spring MVC : java.lang.IllegalStateException: getOutputStream() has already been called for this response Spring:java.lang.IllegalStateException:已经为此响应调用了getOutputStream() - Spring: java.lang.IllegalStateException: getOutputStream() has already been called for this response
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM