8

動作が安定しないサーブレットを実装しました。コンテンツにヘッダーが混在し、同じものを 2 回書き込む場合があります。

また、次のようなコンテンツが混在する応答ヘッダーを含むファイルを返す場合もあります。

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 ヘッダーが挿入されていませんが、HTTP ヘッダーが正しくなく、間違ったファイル名を返します。ファイルの内容は正しいファイルです。リターン転送エンコーディングがチャンクされていると、サーブレットから間違ったリターンが発生することに気付きました。

ヘッダーとバイトの 2 番目の部分を削除すると、有効なファイルになります。同期の問題である可能性はありますか?

UPDATE サーブレットの完全なソースは次のとおりです。

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

更新 * IFrame で必要なパラメーターとセットを使用してサーブレットの URL を生成しているときに、GWT アプリケーションから呼び出しが行われ、サーブレットが呼び出されてファイルがダウンロードされます。何か提案はありますか?*

4

1 に答える 1

2

私はずっと前に同様の問題を抱えていました。ServletOutputStream を閉じると、リクエスト フローで予期しない動作が発生することが判明しました。

サーブレットは、コンテナーが提供する OutputStream を閉じることは想定されていません。別の問題は、コンテンツの長さを手動で設定することである可能性があります。これは、正しい値を生成するコンテナーの責任です。

要約すると、削除out.close()してみてくださいresponse.setContentLength()

于 2012-11-30T20:23:11.577 に答える