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


96

이 방법은

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);
    }

4
이처럼보기는 어렵지만, 앞으로 전달하기 전에 이미 일부 출력을 보낸 것 같습니다. 전체 코드를 인쇄하여 필터가 없는지 확인해 주시겠습니까?
Kartoch

답변:


244

우선 간의 일반적인 오해는 그들이의 전화라고 생각한다는 것입니다 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을 얼마나 자주 닫아야합니까?를 참조하십시오.


2
휴식이란 말은 break;? 이는 코드가 루프 중에 반복적으로 호출 된 일부 for또는 while루프 내부에 있음을 의미합니다 forward()(따라서 부정확하므로 루프 후에 한 번만 호출해야합니다. 아니면 루프가 필요하지 않기 때문에 루프를 제거해야합니다). .
BalusC

@BalusC이 관련 문제에 대한 아이디어가 있습니까? stackoverflow.com/questions/18658021/...
confile

@confile : 저는 Grails를하지 않지만, 호출 스택을 기반으로하여 호출을 수행 forward()하지 않는 동안 여전히 호출을 수행합니다. 내가 잘 알고있는 JSF는 명시 적으로 FacesContext#responseComplete(). 이 관련 질문 ( "grails prevent render response"라는 키워드 사용)이 도움이 될 수 있습니다. stackoverflow.com/questions/5708654/…
BalusC

@BalusC Grails는 기본적으로 Java이지만 문제는 Servlet과 관련이 있습니다. 내가 무엇을 할 수 있는지 다른 생각이 있습니까? 나는 당신이 제안한대로 각 렌더링 후 리디렉션하고 전달합니다.
confile

@confile : 알아요. 나는 이미 그 원인에 답했다 : Grails는 forward()그렇게해서는 안되는 동안 여전히 호출을 수행 하고있다. 해결책은 기능적으로 분명합니다. 그렇게하지 말라고 말하세요. 즉, Grails가해야 할 일인 응답 처리를 프로그래밍 방식으로 인수했다는 사실은 전혀 몰랐습니다. 기술적으로 Grails에게 어떻게 말해야할지 모르겠습니다. 그러나 JSF, Spring MVC, Wicket 등과 같은 다른 많은 MVC 프레임 워크가이를 지원한다는 것을 알고 있습니다 (응답 자체를 처리하지 않도록 지시 받음). Grails에서 이것이 불가능하다면 놀랄 것입니다.
BalusC 2013 년

19

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

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

6

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

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

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

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

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

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

행운을 빕니다!


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 ()를 넣어이 문제를 해결할 수도 있습니다.


2

나는 지웠다

        super.service(req, res);

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


2

충돌...

나는 단지 같은 오류가 있었다. 메서드를 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()모범 사례 를 다시 읽어야 합니다.


1

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

예:

forwardind 인 경우

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

리디렉션하는 경우

    response.sendRedirect(roundTripURI);
    return;

0

반환 방법 후 다음과 같이 간단하게 수행 할 수 있습니다.

return null;

현재 범위를 깰 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.