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


96

Javaサーブレットでは、response.getOutputStream()またはを介して応答本文にアクセスできますresponse.getWriter()。それが書かれた後.close()、これを呼び出す必要OutputStreamがありますか?

一方で、常にOutputStreamsを閉じるというブロッホの勧めがあります。一方、この場合は、閉じる必要のある基になるリソースがあるとは思いません。永続的な接続などを可能にするために、ソケットの開閉はHTTPレベルで管理されます。


閉じられる基になるリソースがあるかどうかを推測する必要はありません。場合は、実装はそう考え、というかそう知っている、彼が提供されますclose()何もしないことを。あなたすべきことは、すべてのクローズ可能なリソースをクローズすることです。
ローン侯爵

1
あなたのコードがそれを開かなかったとしても?私はそうは思いません...
Steven Huwig

回答:


93

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

たとえば、ストリームを閉じた場合、Filterを実装した場合は使用できません。

以上のことをすべて言っても、閉じても、再度使用しない限り問題はありません。

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

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

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

論文

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


2
これは正しいです。注意すべき点の1つは、ストリームをフラッシュする必要がある場合があることです。これは完全に許容されます。
トルジュ2009

1
ライターを閉じると、別の副作用があります。また、ステータスコードを閉じた後は、response.setStatusでステータスコードを設定することもできません。
che javara 2013

1
このアドバイスに従ってください。それはあなたに多くの痛みを救います。なぜそれをしているのかを知らない限り、私はflush()もしません-コンテナにバッファリングを処理させるべきです。
Hal50000 2014年

75

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

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

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


私はこの答えに同意する、あなたも)(ServletResponse.flushBufferをチェックアウト見たいことがあります。docs.oracle.com/javaee/1.4/api/javax/servlet/...
サイバー僧侶

14
「ストリームを開いた場合は、閉じる必要があります。閉じなかった場合は、閉じないでください」---よく言った
Srikanth Reddy Lingala

2
教育委員会に掲示されている文章のように感じます。「開く場合は閉じる。電源を入れる場合はオフにする。ロックを解除する場合はロックする。[...]」
Ricardo

Ivは、コードの早い段階でストリームを使用し、二度とクライアントがサーブレット全体が実行されるのを待たないことに気づきましたが、ストリームの処理が終了したときにclose()クライアントを呼び出すと、クライアントはすぐに戻り、サーブレットの残りの部分は実行を続けます。その後、答えをもう少し相対的にしませんか?決定的なyesまたはnoとは対照的に、
BiGGZ

「ストリームを開いた場合は閉じてください。開いていない場合は閉じないでください。コードが対称であることを確認してください。」-では、このストリームをラップする別のストリームを作成するとどうなるでしょうか。この場合、対称を維持するのは困難です。通常、外側のストリームを閉じると、ネストされたストリームが閉じられます。
steinybot 2017年

5

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


このコメントを追加していただきありがとうございます。陽気に私はまだ少し問題に取り組んでいます-ちょうど今、NetBeansのサーブレットテンプレートが出力ストリームを閉じるためのコードを含んでいることに気づきました...
Steven Huwig

4

ストリームを閉じる必要があります。通常は単に使用して閉じようとしない場合、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には何の問題もありませんでした。古いものでも新しいものでも、問題はないと思います。


4
「ストリームを閉じる必要があります。コードはよりクリーンです...」-私にとって、.close()でペッパー化されたコードは、特に.close()が不要な場合、コードなしのコードよりも見た目が悪くなります-これがこの質問です決定しようとしています。
Steven Huwig、2009

1
うん、でも美しさは次のとおりです:)とにかく、APIが明確ではないので閉じたいので、コードに一貫性があるように見えます。
adrian.tarau 2009

自分のコードで出力ストリームを閉じることは良い習慣ではないと思います。それがコンテナの仕事です。
JimHawkins

get *はストリームを作成せず、プロデューサーではありません。閉じないでください。コンテナで閉じる必要があります。
dmatej

3

を閉じることに対する別の議論OutputStream。このサーブレットを見てください。例外をスローします。例外は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 EE 6、Netbeans 7.4を使用してテスト済み。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.