2009-04-27 37 views
57

Theo mặc định, Tomcat sẽ gửi lại một số nội dung HTML cho khách hàng nếu nó gặp phải một lỗi HTTP 404. Tôi biết rằng thông qua web.xml<error-page>can be configured để tùy chỉnh nội dung này.Vô hiệu hóa tất cả nội dung phản hồi lỗi HTTP mặc định trong Tomcat

Tuy nhiên, tôi chỉ muốn Tomcat gửi không gửi bất kỳ nội dung nào về nội dung phản hồi (tôi vẫn muốn mã trạng thái). Có cách nào để dễ dàng cấu hình điều này?

Tôi đang cố tránh A) gửi nội dung trống trên luồng phản hồi từ Servlet của tôi và B) định cấu hình các trang lỗi tùy chỉnh cho toàn bộ trạng thái lỗi HTTP trong số web.xml của mình.

Đối với một số nền, Tôi đang phát triển một API HTTP và đang kiểm soát nội dung trả lời của riêng tôi. Vì vậy, đối với một HTTP 500, ví dụ, tôi đang điền một số nội dung XML vào phản hồi có chứa thông tin lỗi. Đối với các tình huống như HTTP 404, trạng thái phản hồi HTTP đủ cho khách hàng và nội dung tomcat đang gửi là không cần thiết. Nếu có một cách tiếp cận khác, tôi mở cửa để nghe nó.

Chỉnh sửa: Sau khi tiếp tục điều tra, tôi vẫn không thể tìm thấy nhiều trong cách giải pháp. Nếu ai đó dứt khoát có thể nói điều này là không thể, hoặc cung cấp một nguồn tài liệu với bằng chứng rằng nó sẽ không hoạt động, tôi sẽ chấp nhận điều đó như một câu trả lời và thử và làm việc xung quanh nó.

+6

tôi không quá tải ý nghĩa của các mã, tôi đang sử dụng chúng như họ đang dự định. Đây là một API REST - ví dụ, nếu ai đó thực hiện GET trên một tài nguyên nhất định trong API của tôi và tôi không tìm thấy nó, tôi sẽ đặt trạng thái phản hồi thành 404. Nếu tôi gặp lỗi lạ , Tôi đặt trạng thái 500 và cung cấp một số nội dung lỗi trong phản hồi. Nhưng tôi muốn kiểm soát độc quyền nội dung này - tôi không muốn Tomcat trả lại HTML hoặc bất kỳ thứ gì khác. Nếu nội dung được trả lại, tôi muốn Servlet của tôi là người làm việc đó. –

+4

tôi chỉ còn thấy rằng Servlet 3 dường như cho phép cho một-bắt-tất cả : http://static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/reference/html/mvc.html# mvc-ann-customer-servlet-container-error-page –

+0

@ErichEichinger - Đó là thông tin hữu ích, cảm ơn bạn đã vượt qua nó. –

Trả lời

39

Nếu bạn không muốn tomcat để hiển thị một trang lỗi, sau đó không sử dụng sendError (...). Thay vào đó hãy sử dụng setStatus (...).

ví dụ: nếu bạn muốn trả lời 405, thì bạn làm

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

Cũng nhớ đừng ném bất kỳ ngoại lệ nào từ servlet của bạn. Thay vào đó, hãy nắm bắt ngoại lệ và, một lần nữa, đặt statusCode là tự của bạn.

ví dụ:

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

tất nhiên, nếu bạn không muốn bất kỳ nội dung, sau đó chỉ cần không viết bất cứ điều gì để các nhà văn, chỉ cần thiết lập trạng thái.

+0

Sử dụng 'print()' thay vì 'println()' làm thêm dòng char mới. Điều này đặc biệt hữu ích nếu bạn đang gửi chuỗi rỗng, với 'Content-Length: 0' – manikanta

+3

Tôi nghĩ lý do thực sự tại sao nó hoạt động là vì bạn đã viết cho luồng đầu ra. Tôi tin rằng nếu bạn chỉ cần thiết lập trạng thái và không viết bất cứ điều gì để phản hồi, Tomcat sẽ gửi phản hồi lỗi mặc định cho 405. –

+0

Đơn giản chỉ cần đặt mã trạng thái dường như không đủ để ngăn trang lỗi chuẩn (ít nhất, không dựa trên kinh nghiệm của riêng tôi). –

2

Tại sao không chỉ cần cấu hình các yếu tố <error-page> với một trang HTML trống rỗng?

+1

Tôi đã đề cập trong câu hỏi của mình rằng tôi muốn tránh định cấu hình các trang lỗi (ngay cả khi chúng trống) cho một loạt trạng thái. Nếu đó là lựa chọn duy nhất của tôi sau đó tôi đoán tôi sẽ phải - nhưng tôi đang tìm kiếm lựa chọn thay thế. –

9

Như Heikki đã nói, đặt trạng thái thay vì sendError() khiến Tomcat không chạm vào đối tượng phản hồi/cơ thể/trọng tải.

Nếu bạn chỉ muốn gửi các tiêu đề phản ứng mà không cần bất kỳ tổ chức nào, như trong trường hợp của tôi,

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

hiện các trick.Với Content-Length: 0, các print() sẽ không có hiệu lực ngay cả khi sử dụng, như:

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

khách hàng nhận được một cái gì đó như:

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 

Nếu bạn muốn gửi một số thông báo lỗi, sử dụng setContentLength() với chiều dài nhắn (khác với số không) hoặc bạn có thể để nó vào máy chủ

8

Cách nhanh chóng, hơi bẩn, nhưng dễ dàng ngăn chặn Tomcat gửi bất kỳ cơ thể lỗi nào là gọi setErrorReportValveClass với máy chủ tomcat, với một van báo cáo lỗi tùy chỉnh ghi đè báo cáo để không làm gì cả. ví dụ:

public class SecureErrorReportValve extends ErrorReportValve { 

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

} 

và đặt nó với:

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

Nếu bạn muốn gửi thông điệp của bạn, và chỉ nghĩ Tomcat không nên gây rối với nó, bạn muốn một cái gì đó dọc theo dòng:

@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

này làm việc tuyệt vời! Tôi thích có một nơi duy nhất để kiểm soát điều này thay vì phải quấn từng câu trả lời. Nhiều khía cạnh theo định hướng. – mckamey

+0

Thực sự là một giải pháp tốt hơn! Cảm ơn – Poni

+0

Không phải là một giải pháp tốt, bạn đang đi ngược lại speclet servlet. –

1

Mặc dù câu hỏi này hơi cũ, tôi cũng gặp sự cố này. Trước hết, hành vi của Tomcat là hoàn toàn chính xác. Đây là mỗi Servlet Spec. Người ta không nên thay đổi hành vi của Tomcat chống lại spec. Như Heikki Vesalainen và mrCoder đã đề cập, chỉ sử dụng setStatussetStatus.

Đối với người mà nó có thể quan tâm, tôi đã nêu một số ticket với Tomcat để cải thiện tài liệu của sendError.

+1

Bạn có thể làm rõ ý nghĩa của hành vi là "hoàn toàn chính xác" không? Hành vi nào, cụ thể? Một liên kết hoặc trích đoạn từ đặc tả Servlet có thể hữu ích. Tôi không thể tìm thấy bất kỳ điều gì trong đặc tả 3.0 giải quyết các yêu cầu về nội dung thực tế của phản hồi, đặc biệt là đối với các phản hồi lỗi. Theo như [RFC2616] (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html), không có bất kỳ yêu cầu nào về nội dung thực thể đối với bất kỳ trạng thái lỗi nào. –

+0

Vâng, tất nhiên rồi. Điều này không bị ràng buộc với RFC mà chính là bản thân Servlet. Kiểm tra Servlet spec 3.0, chương 10.9.2 và 10.9.3, JavaDocs của Servlet API của Java cho cả hai '' sendError'] (http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse. phương thức html # sendError% 28int% 29) và câu hỏi của tôi cho [Danh sách gửi thư của người dùng Tomcat] (http://www.mail-archive.com/[email protected]/msg102755.html). –

5

Mặc dù đó là đặc tả Servlet spec, vì lý do bảo mật, tôi không muốn tomcat hoặc bất kỳ vùng chứa Servlet nào khác gửi chi tiết lỗi. Tôi đã vật lộn với điều này một chút. Sau khi tìm kiếm và cố gắng, giải pháp có thể được tóm tắt như:

  1. như những người khác đã đề cập, không sử dụng sendError(), sử dụng setStatus() thay
  2. khuôn khổ như ví dụ Bảo mật mùa xuân sử dụng sendError() mặc dù ...
  3. viết Filter rằng
    a. chuyển hướng cuộc gọi đến sendError() tới setStatus()
    b. tuôn ra phản ứng ở cuối để ngăn không cho container tiếp tục sửa đổi phản hồi

A little example servlet filter doing this can be found here.

+1

+1 để chỉ ra rằng các khuôn khổ có hành vi được xác định trước và cung cấp một bộ lọc mẫu, mà - như tôi đang sử dụng [Jersey] (https://jersey.java.net /) - giúp tôi khám phá [một thuộc tính Jersey cụ thể] (https://jersey.java.net/apidocs/2.5/jersey/org/glassfish/jersey/server/ServerProperties.html#RESPONSE_SET_STATUS_OVER_SEND_ERROR) – watery

28

Mặc dù điều này không phản hồi chính xác câu hỏi "không gửi bất kỳ điều gì" trên câu hỏi và trên wave Clive Evans' answer, tôi phát hiện ra rằng trong tomcat, bạn có thể làm cho những văn bản dài dòng đó biến mất khỏi các trang lỗi tạo một ErrorReportValve tùy chỉnh.

Bạn có thể thực hiện để ErrorReportValve tùy biến này thông qua 2 params "showReport" và "showServerInfo" on "server.xml" của bạn:

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

Link to official documentation.

Làm việc cho tôi trên tomcat 7.0.55, không hoạt động đối với tôi trên tomcat 7.0.47 (Tôi nghĩ rằng vì một cái gì đó đã báo cáo về liên kết sau http://www.mail-archive.com/[email protected]/msg113856.html)

+5

Làm việc với Tomcat 8 Giải pháp tuyệt vời! – eis

+3

Tài liệu Tomcat nói phần tử có thể đi trong các thành phần , hoặc trong tệp server.xml. Đối với tôi đặt van trong phần tử không hoạt động nhưng đặt nó bên trong các phần tử riêng lẻ đã làm. Các tài liệu cũng cho biết Tomcat định tuyến mọi tên máy chủ không phù hợp với phần tử được đặt trong thuộc tính defaultHost của phần tử . Để đảm bảo rằng URL đến vị trí bên ngoài máy chủ/ngữ cảnh của bạn không được hiển thị các thông báo lỗi được biên dịch thành Tomcat, bạn cần đảm bảo rằng này được thêm vào mặc định của bạn. –

Các vấn đề liên quan