java.lang.IllegalStateException 从网络服务器下载文件时出现 servlet 异常

java.lang.IllegalStateException servlet exception when download file from web server

我有一些从网络服务器下载文件的代码。 一切正常,但在控制台中我有这个异常:

        июн 26, 2015 2:08:42 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [default] in context with path [/TestTask] threw exception
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
    at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:462)
    at org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleErrorInDevMode(DefaultDispatcherErrorHandler.java:109)
    at org.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleError(DefaultDispatcherErrorHandler.java:57)
    at org.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:909)
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:576)
    at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

为什么以及可能是什么?我该如何解决这个问题?我尝试在 google 中找到答案,但我失败了。

代码:

package actions;

import java.io.IOException;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.Action;

import org.apache.log4j.Logger;
import org.apache.struts.chain.contexts.ServletActionContext;

import service.CsvCreator;

import com.opensymphony.xwork2.ActionSupport;

public class DownloadCsvAction extends ActionSupport {

    private static final long serialVersionUID = -4714537109287679996L;
    private CsvCreator CSVcreator;
    private static final Logger logger = Logger.getLogger(DownloadCsvAction.class);

    public CsvCreator getCSVcreator() {
        return CSVcreator;
    }

    public void setCSVcreator(CsvCreator cSVcreator) {
        CSVcreator = cSVcreator;
    }

    @Override
    public String execute() {

        HttpServletResponse response = org.apache.struts2.ServletActionContext.getResponse();
        response.setHeader("Content-Disposition", "attachment; filename=\"phone_records.csv\"");
        response.setContentType("text/csv");

        ServletOutputStream out;
        try {
            out = response.getOutputStream();

            String tableHeader = "Caller, Event, Reciever, Timestamp\n";

            out.write(tableHeader.getBytes("UTF-8"));
            out.write(CSVcreator.getAllRecordsInString().getBytes("UTF-8"));
            
            out.flush();
            out.close();
        } catch (IOException e) {
            logger.error(e.getMessage());
        }

        return SUCCESS;
    }

}

还有我的struts.xml:

<action name="DownloadCsvAction" class="DownloadCsvAction">
        <result name="success" type="dispatcher"/>
</action>

Why and what it can be?

因为响应已经提交。 Struts2 使用之前您已关闭响应。

And how I can fix this problem?

当您的操作执行结束时,return Action.NONE 结果代码。此代码告诉调用者不要执行任何结果,因为响应可能已经提交。

您还可以重写操作实现以使用 stream 结果类型。通过这种方式,您不必处理响应,让 Struts2 完成其余的工作。使用 stream 结果的示例是 here