我收到一个异常:java.lang.IllegalStateException: getOutputStream() has been called for this response

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30560360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:49:28  来源:igfitidea点击:

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

javaspring-mvcspring-boot

提问by Tushar

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

采纳答案by hagrawal

  1. 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.
    • IllegalStateExceptionwill be thrown if the getWriter() method has been called on this response object.
  2. HttpServletResponse.getWriter()

    • Returns a PrintWriter object which can be used to write character text (non-binary) data to the client.
    • 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.
    • IllegalStateExceptionwill be thrown if the getOutputStream() method has already been called for this response object
  1. HttpServletResponse.getOutputStream()

    • 用于向客户端写入二进制数据。
    • 写入客户端的数据未编码。
    • 一旦调用flush(),数据就会被刷新到客户端。
    • IllegalStateException如果在此响应对象上调用了 getWriter() 方法,则将抛出。
  2. HttpServletResponse.getWriter()

    • 返回一个 PrintWriter 对象,该对象可用于将字符文本(非二进制)数据写入客户端。
    • 发送到客户端的数据使用默认编码方案或用户提供的编码。
    • 一旦调用flush(),数据就会被刷新到客户端。
    • IllegalStateException如果已经为此响应对象调用了 getOutputStream() 方法,则将抛出

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.

底线:应使用上述 2 种方法中的任何一种将数据刷新到客户端,而不是两者都使用,开发人员必须确保正确处理它,特别是在非 servlet 类中执行操作时。

回答by JB Nizet

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. The method should return void.

那没有意义。它只能是其中之一。如果您希望请求下载文件,则不应返回 ModelAndView。该方法应该返回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。

回答by hagrawal

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()and response.flushBuffer(),这意味着您正在尝试将内容刷新到客户端,然后最后当您的 downloadFileProcess() 返回时,Springs 也在尝试使用刷新内容,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");and 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.

在一个侧面说明,为什么这样做model.setViewName("error");,并model.addObject("message", "Action:" + action);在开始?我认为要么你不应该拥有它,因为你最终会被覆盖,或者它们更适合放在 CATCH 块中。

回答by FoxsTail

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();
}