【问题标题】:Servlet mixes header and content and writing twice same in output?Servlet 混合标题和内容并在输出中写入两次相同?
【发布时间】:2012-11-30 15:07:22
【问题描述】:

我已经实现了 servlet,它的行为不稳定,有时它会在内容中混合标题并两次写入相同的内容。

有时它会返回包含响应头的文件,其中包含以下内容:

Server: Apache-Coyote/1.1
: W/"43-1353687036000"
DatCCoonntenntt--DDiissppoosittiioonn: : atatatacehnmte;n tf;i lfenlaemnea=m20=12201112211127325421_4W1_Wirnkgi_nSgc_Seern.xnlsx
sx
Content-Typ-eT: ype: applaipcatciaoti/on/toctestt-rstare
am
ConCtoententy-pTeype: appalicatcion/oon/octet-setarm
m
CCoonntent-Lnegtht h: 4199

Date: te: FriF,r i2,3  2No vNo2v0 120162: 215:25 :G4M2T 
....
File content bytes ...

And again same header and content

更新 *这种情况发生在 Tomcat7 上*

我也在 Tomcat6 和 Jetty 上进行了测试,在这两种情况下都没有注入 HTTP-Header 到响应内容,但是 HTTP-Header 错误并返回错误的文件名,文件内容是正确的文件。我注意到 servlet 的错误返回发生在 返回传输编码被分块。

当我删除标题内容和字节的第二部分时,它是有效文件。 是否可能是同步问题?

更新 这是 servlet 的完整源代码:

public class ExcelDownloadServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger
            .getLogger (ExcelDownloadServlet.class);


    @Override
    protected void doGet (HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        try
        {
            TransactionId transactionId = getTransactionId (request);
            String fileName =
                    request.getParameter (GlobalConstants.EXCEL_FILE);
            ExcelDownloadType downloadType =
                    ExcelDownloadType
                            .valueOf (request
                                    .getParameter (GlobalConstants.EXCEL_DOWNLOAD_TYPE));
            ActionContextFactory actionContextFactory =
                    ApplicationContext.getContext ()
                            .getActionContextFactory ();
            //suppress warning. HttpServletRequest.getLocales does not support generics
            @SuppressWarnings("unchecked")
            ActionContext actionContext =
                    actionContextFactory.create (request.getSession ()
                            .getId (), Collections.<Locale> list (request
                            .getLocales ()));
            GetExcelDataResponse dataResponse =
                    new GetExcelData (transactionId, fileName, downloadType)
                            .execute (actionContext);
            writeToResponse (response, dataResponse.getFileName (),
                    dataResponse.getData ());
        }
        catch (InvalidSessionException e)
        {
            LOG.error ("Invalid session in Excel download", e);
            throw new ServletException (e);
        }
        catch (ActionException e)
        {
            LOG.error ("Could not download into excel.", e);
            throw new ServletException (e);
        }
    }

    protected TransactionId getTransactionId (HttpServletRequest request)
    {
        return RequestParameterDeserializer.<TransactionId> deserialize (
                request, GlobalConstants.TRANSACTION_ID);
    }

    protected void writeToResponse (HttpServletResponse response,
            String rawFileName, byte[] data) throws IOException
    {
        ServletOutputStream sout = null;
        try
        {            
            response.setContentType ("application/octet-stream");
            response.setContentLength (data.length);
            // removing blanks from the file name, since FF cuts file names
            // otherwise.
            String fileNameWithTime = rawFileName.replaceAll (" ", "_");
            response.setHeader ("Content-Disposition", "attachment; filename="
                    + fileNameWithTime);
            sout = response.getOutputStream ();
            sout.write (data, 0, data.length);
        }
        finally
        {
            if (sout != null)
            {
                sout.close ();
            }
        }
    }

更新 *GWT 应用程序在生成带有所需参数并在 IFrame 中设置的 servlet 的 URL 时调用来自 GWT 应用程序,然后 servlet 调用和文件正在下载。有什么建议吗?*

【问题讨论】:

  • 如果您怀疑存在同步问题,我建议您发布整个 servlet,因为某些同步问题是由 servlet 中定义的字段引起的。
  • @kmb385 我的意思是我应该同步我发布的那部分代码吗?这是一个非常简单的 servlet,它在输出中写入生成文件的给定字节数组,我很困惑为什么它包含响应头等。
  • 由于为每个 servlet 创建了一个新的响应和请求实例,我认为不需要同步这段代码。您能否发布请求 servlet 的 html 或 js。
  • 你有过滤器吗?
  • 确实,似乎有一些 HttpServletResponseWrapper 被错误地执行其工作的过滤器注入。

标签: java servlets synchronization


【解决方案1】:

很久以前我也遇到过类似的问题。 事实证明,关闭 ServletOutputStream 会触发请求流上的意外行为。

Servlet 不应该关闭容器提供的 OutputStream。 另一个问题可能是手动设置内容长度,这是容器产生正确值的责任。

总而言之,尝试删除 out.close()response.setContentLength()

【讨论】:

  • 我已经指定了response.setContentLength(),我会尝试去掉out.close(),这个问题很少出现,难以重现,谢谢解答
猜你喜欢
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 2020-09-14
  • 1970-01-01
  • 2017-07-01
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多