web-dev-qa-db-ja.com

HttpServletResponse.getOutputStream()/。getWriter()で.close()を呼び出す必要がありますか?

いくつかのグーグルでこれに対する信頼できる答えを見つけることができませんでした。 Javaサーブレットでは、response.getOutputStream()またはresponse.getWriter()を介して応答本文にアクセスできます。このストリームへの書き込み後に.close()を呼び出す必要がありますか?

一方では、出力ストリームを常に閉じるためのBlochianの推奨があります。一方、この場合、閉じる必要がある基礎的なリソースがあるとは思わない。ソケットの開閉はHTTPレベルで管理され、永続的な接続などを許可します。

87
Steven Huwig

通常、ストリームを閉じないでください。サーブレットリクエストライフサイクルの一部としてサーブレットの実行が終了すると、サーブレットコンテナは自動的にストリームを閉じます。

たとえば、ストリームを閉じた場合、 Filter を実装すると使用できなくなります。

それをすべて言ったが、あなたがそれを閉じても、あなたがそれを再び使用しようとしない限り、悪いことは何も起こらない。

編集: 別のフィルターリンク

EDIT2:adrian.tarauは、サーブレットが処理を行った後に応答を変更する場合、HttpServletResponseWrapperを拡張するラッパーを作成し、出力をバッファリングする必要があるという点で正しいです。これは、出力がクライアントに直接送られないようにするためですが、次の抜粋(エンファシスマイニング)に従って、サーブレットがストリームを閉じた場合に保護することもできます。

応答を変更するフィルターは、クライアントに返される前に、応答を通常キャプチャする必要があります。これを行う方法は、応答を生成するサーブレットをスタンドインストリームに渡すことです。代行ストリームは、サーブレットが完了したときにサーブレットが元の応答ストリームを閉じるのを防ぎ、フィルターがサーブレットの応答を変更できるようにします。

記事

公式のSunの記事から、サーブレットからの出力ストリームを閉じることは通常のことですが、必須ではないことが推測できます。

85
Nemi

一般的なルールは次のとおりです。ストリームを開いた場合は、閉じる必要があります。しなかったなら、すべきではありません。コードが対称であることを確認してください。

HttpServletResponseの場合、getOutputStream()の呼び出しがストリームを開く操作であるかどうかは明らかではないため、少し明確ではありません。 Javadocは「_Returns a ServletOutputStream_」とだけ言っています。 getWriter()についても同様です。いずれにせよ、明らかなことは、HttpServletResponseがストリーム/ライターを「所有」しており、それ(またはコンテナー)が再びそれを閉じることです。

したがって、あなたの質問に答えるために-いいえ、この場合はストリームを閉じないでください。コンテナはそれを行う必要があり、その前にコンテナに入ると、アプリケーションにわずかなバグが混入する危険があります。

69
skaffman

「含まれる」リソースでフィルターが呼び出される可能性がある場合は、間違いなくnotストリームを閉じる必要があります。これにより、インクルードリソースが「ストリームクローズ」例外で失敗します。

4
Skip Head

ストリームを閉じる必要があります。getOutputStream()を呼び出すと、コードはよりクリーンになります。通常、ストリームを使用するだけで閉じようとしない場合、ストリームはパラメータとして渡されません。サーブレットAPIには、出力ストリームを閉じることができるか、閉じてはならない場合、この場合は安全にストリームを閉じることができるとは記載されていません。

Jettyのclose()メソッドは次のとおりです。閉じられていない場合、ストリームを閉じます。

public void close() throws IOException
    {
        if (_closed)
            return;

        if (!isIncluding() && !_generator.isCommitted())
            commitResponse(HttpGenerator.LAST);
        else
            flushResponse();

        super.close();
    }

また、Filterの開発者として、OutputStreamが閉じられていないと想定しないでください。サーブレットがジョブを実行した後にコンテンツを変更する場合は、常に別のOutputStreamを渡す必要があります。

編集:私は常にストリームを閉じていますが、Tomcat/Jettyで問題はありませんでした。古いコンテナでも新しいコンテナでも問題はないはずです。

3
adrian.tarau

OutputStreamを閉じることに対するもう1つの引数。このサーブレットを見てください。例外をスローします。例外はweb.xmlでエラーJSPにマッピングされます。

_package ser;

import Java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(name = "Erroneous", urlPatterns = {"/Erroneous"})
public class Erroneous extends HttpServlet {

  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("text/html;charset=UTF-8");
    PrintWriter out = resp.getWriter();
    try {
      throw new IOException("An error");
    } finally {
//      out.close();
    }
  }
}
_

Web.xmlファイルには次が含まれます。

_<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://Java.Sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <error-page>
        <exception-type>Java.io.IOException</exception-type>
        <location>/error.jsp</location>
    </error-page>
</web-app>
_

そして、error.jsp:

_<%@page contentType="text/html" pageEncoding="UTF-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Error Page</title>
    </head>
    <body>
        <h1><%= exception.getMessage()%></h1>
    </body>
</html>
_

ブラウザに_/Erroneous_をロードすると、「エラー」を表示するエラーページが表示されます。ただし、上記のサーブレットでout.close()行のコメントを解除し、アプリケーションを再デプロイして、_/Erroneous_を再ロードすると、ブラウザには何も表示されません。実際に何が起こっているのかはわかりませんが、out.close()がエラー処理を妨げていると思います。

Tomcat 7.0.50でテスト済み、Java NetBeans 7.4を使用するEE 6。

3
user1872904