Вопрос-ответ

Should one call .close() on HttpServletResponse.getOutputStream()/.getWriter()?

Следует ли вызывать .close() для HttpServletResponse.getOutputStream()/.getWriter()?

В сервлетах Java можно получить доступ к телу ответа через response.getOutputStream() или response.getWriter(). Следует ли вызывать .close() это OutputStream после того, как оно было записано в?

С одной стороны, есть блохианское требование всегда закрывать OutputStreams . С другой стороны, я не думаю, что в этом случае есть базовый ресурс, который нужно закрывать. Открытие / закрытие сокетов управляется на уровне HTTP, чтобы разрешить такие вещи, как постоянные соединения и тому подобное.

Переведено автоматически
Ответ 1

Обычно вам не следует закрывать поток. Контейнер сервлета автоматически закроет поток после завершения работы сервлета как части жизненного цикла запроса сервлета.

Например, если вы закрыли поток, он был бы недоступен, если бы вы реализовали фильтр.

Сказав все это, если вы закроете его, ничего плохого не произойдет, пока вы не попытаетесь использовать его снова.

РЕДАКТИРОВАТЬ: другая ссылка для фильтра

ПРАВКА 2: adrian.tarau прав в том, что если вы хотите изменить ответ после того, как сервлет выполнил свою задачу, вы должны создать оболочку, расширяющую HttpServletResponseWrapper, и буферизовать выходные данные. Это сделано для того, чтобы выходные данные не передавались напрямую клиенту, но также позволяет вам защитить, если сервлет закроет поток, согласно этому отрывку (выделено мной):


Фильтр, который изменяет ответ, должен обычно фиксировать ответ, прежде чем он будет возвращен клиенту. Способ сделать это - передать сервлету, генерирующему ответ, резервный поток. Резервный поток не позволяет сервлету закрыть исходный поток ответов после его завершения и позволяет фильтру изменять ответ сервлета.


Статья

Из этой официальной статьи Sun можно сделать вывод, что закрытие OutputStream из сервлета является обычным явлением, но не обязательным.

Ответ 2

Общее правило для них таково: если вы открыли поток, вам следует его закрыть. Если вы этого не сделали, вам не следует. Убедитесь, что код симметричен.

В случае с HttpServletResponse это немного менее понятно, поскольку не очевидно, является ли вызов getOutputStream() операцией, которая открывает поток. Javadoc просто говорит, что это "Returns a ServletOutputStream"; аналогично для getWriter(). В любом случае, ясно, что HttpServletResponse "владеет" потоком / записью, и он (или контейнер) отвечает за его повторное закрытие.

Итак, отвечая на ваш вопрос - нет, вам не следует закрывать поток в этом случае. Это должен сделать контейнер, и если вы войдете туда раньше него, вы рискуете внести незначительные ошибки в ваше приложение.

Ответ 3

Если есть какой-либо шанс, что фильтр может быть вызван для "включенного" ресурса, вам определенно не следует закрывать поток. Это приведет к сбою включаемого ресурса с исключением "поток закрыт".

Ответ 4

Еще один аргумент против закрытия 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>

И ошибка.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>
<h3><%= exception.getMessage()%></h3>
</body>
</html>

При загрузке /Erroneous в браузере вы видите страницу с ошибкой, отображающую "Ошибка".
Но если вы откомментируете out.close() строку в приведенном выше сервлете, повторно развернете приложение и перезагрузите его, /Erroneous вы ничего не увидите в браузере. Я понятия не имею, что происходит на самом деле, но я предполагаю, что out.close() предотвращает обработку ошибок.

Протестировано с Tomcat 7.0.50, Java EE 6 с использованием Netbeans 7.4.

java servlets