itsource

HttpServletResponse.getOutputStream()/.getWriter()에서 .close()를 호출해야 합니까?

mycopycode 2022. 9. 29. 00:18
반응형

HttpServletResponse.getOutputStream()/.getWriter()에서 .close()를 호출해야 합니까?

Java Servlet에서는 응답 본문에 액세스 할 수 있습니다.response.getOutputStream()또는response.getWriter()1명이 전화를 걸면.close()이것에 대해서OutputStream그 편지를 쓴 후에?

한편으로, 블로키아의 권고가 있다. 항상 닫으라는 것이다.OutputStreams. 한편, 이 경우 폐쇄할 필요가 있는 기초적인 자원이 있다고는 생각하지 않습니다.소켓의 개폐는 HTTP 수준에서 관리되므로 영속적인 접속 등을 할 수 있습니다.

일반적으로 스트림을 닫으면 안 됩니다.서블릿 요청 수명 주기의 일부로 서블릿 실행이 완료되면 서블릿 컨테이너가 자동으로 스트림을 닫습니다.

예를 들어 스트림을 닫으면 필터를 구현하면 스트림을 사용할 수 없습니다.

그렇다고 해도, 닫으면 다시 사용하지 않는 한, 나쁜 일은 일어나지 않습니다.

EDIT: 다른 필터 링크

EDIT2: adrian.tarau는 서블릿이 동작한 후 응답을 변경하려면 Http Servlet Response Wrapper를 확장한 래퍼를 생성하여 출력을 버퍼링해야 한다는 점에서 정확합니다.이는 출력이 클라이언트에 직접 전송되지 않도록 하기 위한 것이지만 다음 발췌(강조)에 따라 서블릿이 스트림을 닫았을 경우에도 보호할 수 있습니다.

응답을 수정하는 필터는 일반적으로 클라이언트에 반환되기 전에 응답을 캡처해야 합니다.이 방법은 응답을 생성하는 서블릿을 스탠드인 스트림으로 전달하는 것입니다.스탠드인 스트림은 완료 시 서블릿이 원래 응답 스트림을 닫는 것을 방지하고 필터가 서블릿의 응답을 수정할 수 있도록 합니다.

기사

Sun의 공식 기사로부터 유추할 수 있습니다.OutputStreamservlet은 일반적인 발생이지만 필수는 아닙니다.

일반적인 규칙은 스트림을 열었으면 닫아야 한다는 것입니다.안 그랬으면 안 그랬어야죠.코드가 대칭인지 확인합니다.

의 경우HttpServletResponse, 조금 덜 명확합니다.왜냐하면 전화를 걸어도 명확하지 않기 때문입니다.getOutputStream()스트림을 여는 작업입니다.자바독은 그저 이렇게 말한다.Returns a ServletOutputStream"; 마찬가지로getWriter()어느 쪽이든 분명한 건HttpServletResponse스트림/라이터를 "삭제"하면 스트림/라이터(또는 컨테이너)가 다시 닫는 역할을 합니다.

이 경우 스트림을 닫으면 안 됩니다.컨테이너는 이 작업을 수행해야 하며, 컨테이너보다 먼저 컨테이너에 들어가면 애플리케이션에 미묘한 버그가 발생할 위험이 있습니다.

포함된 리소스에서 필터를 호출할 가능성이 있는 경우 스트림을 닫지 마십시오.이로 인해 포함 리소스가 실패하고 '스트림 닫힘' 예외가 발생합니다.

스트림을 닫아야 합니다.getOutputStream()을 호출하면 스트림이 파라미터로 전달되지 않기 때문에 스트림을 닫아야 합니다.일반적으로 스트림을 닫으려고 하지 않을 때는 스트림이 파라미터로 전달되지 않습니다.Servlet API는 출력 스트림을 닫을 수 있거나 닫을 수 없는 경우 스트림을 안전하게 닫을 수 있다고 명시하지 않습니다. 이 경우 서블릿에 의해 닫히지 않은 경우 모든 컨테이너가 스트림을 닫습니다.

다음은 Jetty의 close() 메서드입니다.스트림이 닫히지 않으면 스트림이 닫힙니다.

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

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

        super.close();
    }

또한 필터 개발자는 OutputStream이 닫히지 않았다고 가정해서는 안 됩니다.서블릿이 작업을 완료한 후 콘텐츠를 변경하려면 항상 다른 OutputStream을 전달해야 합니다.

편집 : 항상 스트림을 닫고 있으며 Tomcat/Jetty에서는 문제가 없었습니다.오래된 컨테이너든 새 컨테이너든 문제가 없을 것 같아요.

또 다른 반대 논거는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>
        <h1><%= exception.getMessage()%></h1>
    </body>
</html>

로드 시/Erroneous브라우저에 "An error"라는 오류 페이지가 나타납니다.하지만 코멘트를 해제하면out.close()위의 서블릿 행, de 어플리케이션 재배포 및 새로고침/Erroneous브라우저에는 아무것도 표시되지 않습니다.실제로 무슨 일이 일어나고 있는지는 모르겠지만, 제 생각엔out.close()에러 처리를 방지합니다.

Netbeans 7.4를 사용하여 Tomcat 7.0.50, Java EE 6에서 테스트되었습니다.

스프링 보안과 함께 스프링을 사용하는 경우 스트림이나 라이터를 닫지 마십시오.

반환된 스트림ServletResponse.getOutputStream()또는 에서 돌아온 작가ServletResponse.getWriter()닫으면 응답이 커밋됩니다.여기서 설명한 것처럼 응답을 커밋하는 것은 http 상태와 헤더가 불변하게 되어 Spring 프레임워크는 이 요청 처리 중에 예외가 발생하더라도 http 상태를 조정할 수 없음을 의미합니다.

의 예OnCommittedResponseWrapperclass는 의 구현으로 사용됩니다.ServletResponse이 동작의 원인이 되는 코드는 다음과 같습니다(javadoc도 체크해 주세요).

컨트롤러의 예를 다음에 나타냅니다.

@RestController
public class MyController {
    @RequestMapping(method = RequestMethod.POST, value = "/blah")
    public void entrypoint(ServletRequest request, ServletResponse response) throws IOException {
        try (var writer = response.getWriter()) {
            throw new RuntimeException("Something bad happened here");
        }
    }

예외가 발생했을 때 가장 먼저 발생하는 것은 에 대한 콜입니다.writer.close()응답 http 상태를 기본값으로 동결합니다.200.

그 후에만 예외는 이 컨트롤러에서 스프링오류 핸들러로 전파되기 시작합니다.스프링 오류 핸들러는 상태를 다음과 같이 변경할 수 없습니다.500응답은 이미 커밋되어 있기 때문에 상태는 유지됩니다.200.

언급URL : https://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter

반응형