[servlets] java.lang.IllegalStateException : 응답이 커밋 된 후 (forward | sendRedirect | create session) 수 없습니다.

이 방법은

java.lang.IllegalStateException : 응답이 커밋 된 후 전달할 수 없습니다.

문제를 발견 할 수 없습니다. 도움이 필요하세요?

    int noOfRows = Integer.parseInt(request.getParameter("noOfRows"));
    String chkboxVal = "";
    // String FormatId=null;
    Vector vRow = new Vector();
    Vector vRow1 = new Vector();
    String GroupId = "";
    String GroupDesc = "";
    for (int i = 0; i < noOfRows; i++) {
        if ((request.getParameter("chk_select" + i)) == null) {
            chkboxVal = "notticked";
        } else {
            chkboxVal = request.getParameter("chk_select" + i);
            if (chkboxVal.equals("ticked")) {
                fwdurl = "true";
                Statement st1 = con.createStatement();
                GroupId = request.getParameter("GroupId" + i);
                GroupDesc = request.getParameter("GroupDesc" + i);
                ResultSet rs1 = st1
                        .executeQuery("select FileId,Description from cs2k_Files "
                                + " where FileId like 'M%' and co_code = "
                                + ccode);
                ResultSetMetaData rsm = rs1.getMetaData();
                int cCount = rsm.getColumnCount();

                while (rs1.next()) {
                    Vector vCol1 = new Vector();
                    for (int j = 1; j <= cCount; j++) {
                        vCol1.addElement(rs1.getObject(j));
                    }
                    vRow.addElement(vCol1);
                }
                rs1 = st1
                        .executeQuery("select FileId,NotAllowed from cs2kGroupSub "
                                + " where FileId like 'M%' and GroupId = '"
                                + GroupId + "'" + " and co_code = " + ccode);
                rsm = rs1.getMetaData();
                cCount = rsm.getColumnCount();

                while (rs1.next()) {
                    Vector vCol2 = new Vector();
                    for (int j = 1; j <= cCount; j++) {
                        vCol2.addElement(rs1.getObject(j));
                    }
                    vRow1.addElement(vCol2);
                }

                // throw new Exception("test");

                break;
            }
        }
    }
    if (fwdurl.equals("true")) {
        // throw new Exception("test");
        // response.sendRedirect("cs2k_GroupCopiedUpdt.jsp") ;
        request.setAttribute("GroupId", GroupId);
        request.setAttribute("GroupDesc", GroupDesc);
        request.setAttribute("vRow", vRow);
        request.setAttribute("vRow1", vRow1);
        getServletConfig().getServletContext().getRequestDispatcher(
                "/GroupCopiedUpdt.jsp").forward(request, response);
    }



답변

우선 간의 일반적인 오해는 그들이의 전화라고 생각한다는 것입니다 forward(), sendRedirect()또는 sendError()이에 코드의 나머지를 무시하고, 마술 종료 것이며, 메소드 블록 중 “점프”. 예를 들면 :

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
    }
    forward(); // This is STILL invoked when someCondition is true!
}

따라서 이것은 사실이 아닙니다. 물론 다른 Java 메소드와 다르게 작동하지는 않습니다 System#exit(). 때 someCondition위의 예는 true당신이 이렇게 전화하는거야 forward()sendRedirect()또는 sendError()동일한 요청 / 응답에, 다음 기회는 당신이 예외를 얻을 것이다 :

java.lang.IllegalStateException : 응답이 커밋 된 후 전달할 수 없습니다.

는 IF if문이를 호출 forward()하고 이후에 전화하는거야 sendRedirect()또는 sendError()다음 예외 아래에 발생합니다 :

java.lang.IllegalStateException : 응답이 커밋 된 후 sendRedirect ()를 호출 할 수 없습니다.

이 문제를 해결하려면 return;나중에 문 을 추가해야합니다.

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
        return;
    }
    forward();
}

… 또는 else 블록을 도입합니다.

protected void doXxx() {
    if (someCondition) {
        sendRedirect();
    } else {
        forward();
    }
}

코드에서 근본 원인을 파악하려면 forward(), sendRedirect()또는sendError() 메소드 블록을 종료하거나 코드의 나머지를 건너 뛰는없이. 이것은 특정 코드 라인 이전의 동일한 서블릿 내부에있을 수 있지만 특정 서블릿 이전에 호출 된 서블릿 또는 필터에도있을 수 있습니다.

의 경우 sendError()응답 상태를 설정하는 것이 유일한 목적이라면 setStatus()대신 사용하십시오.


또 다른 가능한 원인은 서블릿이 a forward()가 호출 되는 동안 응답에 기록 하거나 동일한 메서드에서 호출되기 때문입니다.

protected void doXxx() {
    out.write("some string");
    // ... 
    forward(); // Fail!
}

대부분의 서버에서 응답 버퍼 크기는 기본적으로 2KB이므로 2KB 이상을 쓰면 커밋되고 forward()동일한 방식으로 실패합니다.

java.lang.IllegalStateException : 응답이 커밋 된 후 전달할 수 없습니다.

해결책은 분명합니다. 서블릿의 응답에 쓰지 마십시오. 이것이 JSP의 책임입니다. 당신은 그냥 그렇게 요청 속성을 설정하고 그렇게 request.setAttribute("data", "some string")JSP에서 인쇄합니다 ${data}. 서블릿을 올바른 방법으로 사용하는 방법을 배우려면 서블릿 위키 페이지 를 참조하십시오 .


또 다른 가능한 원인은 서블릿이 예를 들어 a forward()가 호출 된 후 응답에 파일 다운로드를 기록하기 때문 입니다.

protected void doXxx() {
    out.write(bytes);
    // ... 
    forward(); // Fail!
}

이것은 기술적으로 불가능합니다. forward()통화 를 제거해야합니다 . 최종 사용자는 현재 열려있는 페이지에 남아 있습니다. 파일 다운로드 후 실제로 페이지를 변경하려는 경우 파일 다운로드 로직을 대상 페이지의 페이지로드로 이동해야합니다.


또 다른 가능한 원인은 forward(), sendRedirect()또는 sendError()메소드가 구식 방식의 형태로 JSP 파일에 포함 된 Java 코드를 통해 호출 된다는 것입니다. <% scriptlets %>이는 2001 년부터 공식적으로 권장되지 않았습니다 . 예를 들면 :

<!DOCTYPE html>
<html lang="en">
    <head>
        ...
    </head>
    <body>
        ...

        <% sendRedirect(); %>

        ...
    </body>
</html>

여기서 문제는 JSP가 템플릿 텍스트 (예 : HTML 코드) out.write("<!DOCTYPE html> ... etc ...")가 발견되는 즉시이를 통해 내부적으로 즉시 작성 한다는 것입니다. 따라서 이것은 이전 섹션에서 설명한 것과 본질적으로 동일한 문제입니다.

해결책은 분명합니다. JSP 파일에 Java 코드를 작성하지 마십시오. 이는 서블릿 또는 필터와 같은 일반 Java 클래스의 책임입니다. 서블릿을 올바른 방법으로 사용하는 방법을 배우려면 서블릿 위키 페이지 를 참조하십시오 .


또한보십시오:


구체적인 문제와 관련이없는 JDBC 코드가 리소스를 유출하고 있습니다. 그것도 수정하십시오. 힌트 는 JDBC에서 Connection, Statement 및 ResultSet을 얼마나 자주 닫아야합니까?를 참조하십시오.


답변

return 문을 추가해도이 예외가 발생합니다. 이에 대한 해결책은 다음 코드뿐입니다.

if(!response.isCommitted())
// Place another redirection


답변

일반적으로 이미 리디렉션을 수행 한 다음 출력 스트림에 더 많은 데이터를 출력하려고하면이 오류가 표시됩니다. 과거에 이것을 본 경우에는 페이지를 리디렉션하려는 필터 중 하나 인 경우가 많지만 여전히 서블릿으로 전달합니다. 서블릿에 대해 즉시 잘못된 것을 볼 수 없으므로 제자리에있는 필터도 살펴보고 싶을 수 있습니다.

편집 : 문제 진단에 대한 더 많은 도움…

이 문제를 진단하는 첫 번째 단계는 예외가 발생하는 위치를 정확히 확인하는 것입니다. 우리는 그것이 선에 의해 던져지고 있다고 가정하고 있습니다.

getServletConfig().getServletContext()
                  .getRequestDispatcher("/GroupCopiedUpdt.jsp")
                  .forward(request, response);

그러나 코드에서 나중에 처리를 시도한 후 출력 스트림으로 출력을 시도하는 코드에서 발생한다는 것을 알 수 있습니다. 위 줄에서 오는 경우이 줄 앞 어딘가에 다음 중 하나가 있음을 의미합니다.

  1. 데이터를 출력 스트림으로 출력하거나
  2. 미리 다른 리디렉션을 수행했습니다.

행운을 빕니다!


답변

서블릿이 더 이상 존재하지 않는 요청 객체에 액세스하려고하기 때문입니다. 서블릿의 forward 또는 include 문은 메소드 블록의 실행을 중지하지 않습니다. 다른 Java 메소드와 마찬가지로 메소드 블록 또는 첫 번째 return 문의 끝까지 계속됩니다.

이 문제를 해결하는 가장 좋은 방법은 논리에 따라 동적으로 페이지 (요청을 전달한다고 가정하는 위치)를 설정하는 것입니다. 그건:

protected void doPost(request , response){
String returnPage="default.jsp";
if(condition1){
 returnPage="page1.jsp";
}
if(condition2){
   returnPage="page2.jsp";
}
request.getRequestDispatcher(returnPage).forward(request,response); //at last line
}

그리고 마지막 줄에서 한 번만 앞으로 나아가십시오 …

각 forward () 뒤에 return 문을 사용하거나 if … else 블록에 각 forward ()를 넣어이 문제를 해결할 수도 있습니다.


답변

나는 지웠다

        super.service(req, res);

그런 다음 잘 작동했습니다.


답변

충돌…

나는 단지 같은 오류가 있었다. 메서드를 super.doPost(request, response);재정의 할 때 doPost()뿐만 아니라 수퍼 클래스 생성자를 명시 적으로 호출 할 때 호출하는 것을 알았습니다.

    public ScheduleServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

super.doPost(request, response);from within doPost()문을 주석 처리하자마자 완벽하게 작동했습니다 …

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //super.doPost(request, response);
        // More code here...

}

말할 필요도없이 super()모범 사례 를 다시 읽어야 합니다.


답변

흐름을 전달하거나 리디렉션하는 동안 return 문을 추가해야합니다 .

예:

forwardind 인 경우

    request.getRequestDispatcher("/abs.jsp").forward(request, response);
    return;

리디렉션하는 경우

    response.sendRedirect(roundTripURI);
    return;