2009-04-27 3 views
57

기본적으로 Tomcat은 HTTP 404와 같은 오류가 발생하면 클라이언트에게 HTML 콘텐츠를 보냅니다. web.xml을 통해 <error-page>can be configured을 통해이 내용을 사용자 정의 할 수 있습니다.톰캣의 모든 기본 HTTP 오류 응답 내용을 사용하지 않음

그러나 나는 단지 톰캣에 대해 을 보내지 않고 응답 내용면에서을 보내지 않습니다. (물론 여전히 상태 코드를 좋아할 것입니다.) 쉽게 구성 할 수있는 방법이 있습니까?

A) 명시 적으로 내 서블릿의 응답 스트림에서 빈 콘텐츠를 보내지 않고 B) 내 전체에서 여러 가지 HTTP 오류 상태에 대한 사용자 지정 오류 페이지를 구성하려고합니다.

일부 배경에서 HTTP API를 개발 중이며 자체 응답 내용을 제어하고 있습니다. 예를 들어, HTTP 500의 경우 오류 정보가 포함 된 응답의 일부 XML 컨텐트를 채 웁니다. HTTP 404와 같은 상황에서는 HTTP 응답 상태가 클라이언트에 충분하며 tomcat이 전송되는 내용은 필요하지 않습니다. 다른 접근법이 있다면, 나는 그것을 듣고 싶어합니다.

편집 : 계속적인 조사를 통해 해결책을 찾지 못했습니다. 누군가가 이것이 가능하지 않다고 분명히 말할 수 있거나 작동하지 않을 것이라는 증거를 자원에 제공한다면, 나는 대답으로 받아 들여 그것을 시도하고 해결할 것입니다.

+6

나는 코드의 의미를 과부하하지 않으므로 의도 한대로 사용하고 있습니다. 이것은 REST API를위한 것입니다. 예를 들어 누군가 내 API에서 특정 리소스에 대해 GET을 수행하고 찾지 못하면 응답 상태를 404로 설정합니다. 이상한 오류가 발생하면 , 나는 상태를 500으로 설정하고 응답에 오류 내용을 제공한다. 하지만이 콘텐트에 대한 독점적 인 통제권을 원합니다. Tomcat이 HTML이나 다른 것을 반환하는 것을 원하지 않습니다. 컨텐트가 리턴되어야한다면, 나는 서블릿이 그것을 수행하기를 원한다. –

+4

서블릿 3은 하나의 캐치를 모두 허용하는 것으로 나타났습니다 : http://static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/reference/html/mvc.html# mvc-ann-customer-servlet-container-error-page –

+0

@ErichEichinger - 유용한 정보입니다. 함께 전달해 주셔서 감사합니다. –

답변

39

바람막이에 오류 페이지가 표시되지 않게하려면 sendError (...)를 사용하지 마십시오. 대신 setStatus (...)를 사용하십시오.

405 응답을주고 싶다면

response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);  
response.getWriter().println("The method " + request.getMethod() + 
    " is not supported by this service."); 

서블릿에서 예외를 던지지 않도록주의하십시오. 대신 Exception을 잡아서 다시 statusCode를 설정하십시오. 물론

protected void service(HttpServletRequest request, 
     HttpServletResponse response) throws IOException { 
    try { 

    // servlet code here, e.g. super.service(request, response); 

    } catch (Exception e) { 
    // log the error with a timestamp, show the timestamp to the user 
    long now = System.currentTimeMillis(); 
    log("Exception " + now, e); 
    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 
    response.getWriter().println("Guru meditation: " + now); 
    } 
} 

, 당신은 콘텐츠를 원하지 않는 경우, 다음 방금 상태를 설정, 작가에 아무것도 쓰지 않는다.

+0

'println()'대신'print()'를 사용하면 새로운 줄 문자가 추가됩니다. 이것은'Content-Length : 0'와 함께 빈 문자열을 보내는 경우에 특히 유용합니다. – manikanta

+3

출력 스트림에 작성했기 때문에 이것이 작동하는 실제 이유가 있다고 생각합니다. 상태를 설정하고 응답에 아무 것도 쓰지 않으면 Tomcat이 405에 대한 기본 오류 응답을 보냅니다. –

+0

상태 코드를 설정하는 것만으로는 표준 오류 페이지를 표시하지 않을 수 있습니다 (최소한, 내 경험에 근거하지 않음). –

2

<error-page> 요소를 빈 HTML 페이지로 구성하지 않는 이유는 무엇입니까?

+1

나는 많은 질문에 대해 오류 페이지를 구성하는 것을 피하고 싶다고 말했다. 그것이 나의 유일한 선택 사항이라면 나는해야 할 것 같아요 -하지만 대안을 찾고 있습니다. –

9

Heikki가 말했듯이 sendError() 대신 상태를 설정하면 Tomcat이 응답 entity/body/payload를 터치하지 않게됩니다.

만 내 경우처럼, 실체없이 응답 헤더를 보내려면

,

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
response.setContentLength(0); 

트릭을 수행합니다.Content-Length: 0으로, print() 같이 사용하더라도 아무런 효과가 없습니다 : 당신은 몇 가지 오류 메시지를 보내려면

HTTP/1.1 401 Unauthorized 
Server: Apache-Coyote/1.1 
Content-Type: text/html;charset=utf-8 
Content-Length: 0 
Date: Wed, 28 Sep 2011 08:59:49 GMT 

, 메시지 길이로 setContentLength()를 사용

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
response.setContentLength(0); 
response.getWriter().print("this string will be ignored due to the above line"); 

클라이언트가 같은 것을 받아 (0이 아닌) 또는 서버에 남겨 둘 수 있습니다.

8

톰캣이 오류 본문을 보내지 못하게하는 빠르고 쉬운 방법은 tomcat 호스트에 대해 setErrorReportValveClass를 호출하는 것입니다. 아무것도하지 않기 위해 보고서를 무시하는 사용자 정의 오류 보고서 밸브. 예 :

public class SecureErrorReportValve extends ErrorReportValve { 

@Override 
protected void report(Request request,Response response,Throwable throwable) { 
} 

} 

을하고 그것을 설정 :

((StandardHost) tomcat.getHost()).setErrorReportValveClass(yourErrorValveClassName); 

당신이 당신의 메시지를 보내려면, 그냥 톰캣이 엉망, 당신의 라인을 따라 뭔가를하지한다고 생각하는 경우 :

@Override 
protected void report(final Request request, final Response response, final Throwable throwable) { 
    String message = response.getMessage(); 
    if (message != null) { 
     try { 
      response.getWriter().print(message); 
      response.finishResponse(); 
     } catch (IOException e) { 
     } 
    } 
} 
+0

위대한 기능을 수행했습니다! 모든 단일 응답을 감싸는 대신이 작업을 제어 할 단일 장소가있는 것이 좋습니다. 애스펙트 지향. – mckamey

+0

실제로 더 나은 해결책입니다! 감사합니다. – Poni

+0

좋은 해결책이 아닙니다. 서블릿 스펙에 어긋납니다. –

1

이 질문은 다소 오래되었지만이 문제도 발생했습니다. 우선, Tomcat의 동작은 절대적으로 정확합니다. 이것은 서블릿 스펙에 따른 것입니다. Tomcat의 동작을 변경해서는 안됩니다. Heikki Vesalainen 및 mrCoder 언급 한대로 setStatussetStatus 경우에만 사용하십시오.

나는 우려 할 수도있는 사람에게 sendError의 문서를 개선하기 위해 Tomcat에서 ticket을 제기했습니다.

+1

"절대적으로 정확한"동작이 무엇을 의미하는지 명확히 할 수 있습니까? 구체적으로 어떤 행동입니까? Servlet 스펙의 링크 또는 일부가 도움이 될 수 있습니다. 3.0 사양에서 응답의 실제 내용, 특히 오류 응답에 대한 요구 사항을 언급 한 내용을 찾을 수 없었습니다. [RFC2616] (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)까지 모든 오류 상태에 대한 엔티티 콘텐츠에 대한 요구 사항은 없습니다. –

+0

물론 가능합니다. 이것은 RFC에 종속되지 않고 서블릿 스펙 자체에 묶여있다. ['sendError'] (http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse)에 대한 서블릿 사양 3.0, 10.9.2 및 10.9.3 장, Oracle 서블릿 API JavaDocs를 확인하십시오. html # sendError % 28int % 29) 방법과 [Tomcat 사용자 메일 링리스트] (http://www.mail-archive.com/[email protected]/msg102755.html)에 대한 제 질문에 대해 설명합니다. –

5

Servlet 스펙을 준수하지만 보안상의 이유로 Tomcat이나 다른 서블릿 컨테이너가 오류 세부 정보를 보내지 않기를 바랍니다. 나는 이것으로 조금 어려움을 겪었다. 검색 및 시도 후, 솔루션은 다음과 같이 요약 될 수있다 :

  1. 다른 사람이 언급 한 바와 같이, 대신
  2. 프레임 워크와 같은 setStatus()를 사용 sendError() 사용하지 않는 예를 들어, 스프링 보안 사용 sendError() 비록 ...
  3. Filter을 작성하십시오.
    a. sendError()setStatus()
    으로 리디렉션합니다. b. 컨테이너가 응답을 추가로 수정하지 못하도록 마지막에 응답을 플러시합니다.

A little example servlet filter doing this can be found here

+1

+1 프레임 워크가 미리 정의 된 동작을 가지고 있으며 예제 필터를 제공한다는 것을 지적하기 위해 +1합니다. [Jersey] (https://jersey.java.net /) - 특정 저지 속성을 발견하게했습니다 (https://jersey.java.net/apidocs/2.5/jersey/org/glassfish/jersey/server/ServerProperties.html#RESPONSE_SET_STATUS_OVER_SEND_ERROR) – watery

28

질문에 "아무것도 보내지 마십시오"문구와 정확히 일치하지 않지만 Clive Evans' answer의 물결에 바람둥이에서는 너무 많은 내용의 텍스트가 오류 페이지에서 벗어나지 않도록 할 수 있습니다. 사용자 정의 ErrorReportValve를 작성합니다.

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false" /> 

Link to official documentation :

당신은 2 PARAMS "showReport"와 "server.xml에"의 "showServerInfo"을 통해이 사용자 정의 ErrorReportValve을 수행 할 수 있습니다.

tomcat 7.0.55에서 나를 위해 일했으며, tomcat 7.0에서 작동하지 않았습니다.47 (나는 다음 링크에보고 된 어떤 것 때문에 생각합니다 http://www.mail-archive.com/[email protected]/msg113856.html)

+5

Tomcat 8로 작업 우수한 솔루션! – eis

+3

Tomcat 문서에 따르면 요소는 server.xml의 , 또는 요소 내에 포함될 수 있습니다. 나를 위해 밸브를 넣어 요소가 작동하지 않았지만 그것을 안으로 넣어 개별 요소 않았다. 또한 Tomcat은 일치하지 않는 호스트 이름을 요소의 defaultHost 속성에 설정된 요소로 라우팅합니다. 호스트/컨텍스트 외부의 위치에 대한 URL이 표시되지 않도록 Tomcat에 컴파일 된 오류 메시지는 에 기본값 이 추가되었는지 확인해야합니다. –