2009-07-08 28 views
39

Tôi đang làm việc trên một dịch vụ web RESTful trong Java. Tôi cần một cách tốt để gửi thông báo lỗi cho khách hàng nếu có điều gì đó sai.Cách gửi đúng thông báo HTTP đến máy khách

Theo số Javadoc, HttpServletResponse.setStatus(int status, String message) không được chấp nhận "do ý nghĩa mơ hồ của thông số thư".

Có cách nào ưu tiên để đặt thông điệp trạng thái hoặc "reason phrase" của phản hồi không? Phương thức sendError(int, String) không thực hiện.

EDIT: Để làm rõ, tôi muốn sửa đổi dòng trạng thái HTTP, tức là "HTTP/1.1 404 Not Found", không phải nội dung của nội dung. Cụ thể, tôi muốn gửi câu trả lời như "HTTP/1.1 400 Missing customerNumber parameter".

+0

Có điều gì sai với cụm từ lý do mặc định mà thùng chứa servlet của bạn trả về khi bạn sử dụng sendError không? – laz

+0

Không có gì đặc biệt sai với nó, chỉ là tôi muốn gửi một thông điệp cụ thể hơn. –

Trả lời

16

Tôi không nghĩ rằng bất kỳ ứng dụng RESTful nào sẽ mong đợi xem cụm từ lý do để tìm ra điều gì đã xảy ra; hầu hết các dịch vụ RESTful mà tôi đã xem/sử dụng sẽ gửi thông tin trạng thái chuẩn và thông báo mở rộng trong phần thân của phản hồi. sendError(int, String) là lý tưởng cho tình huống đó.

+3

Một vài người đã lập luận rằng tôi thậm chí không nên gửi tin nhắn thông qua cụm từ lý do, và tôi đoán tôi bị thuyết phục. Tuy nhiên, tôi không thể sử dụng sendError (int, String) vì container chứa thông điệp. Nếu tôi gọi sendError (400, "blah"), nội dung phản hồi (ít nhất là trong WebSphere) là "Lỗi 400: blah". Không tốt, đặc biệt nếu bạn muốn trả về XML hoặc một số định dạng khắt khe khác. Tôi sẽ gọi setStatus (int) và viết nội dung nội dung bằng tay thay thế. –

0

Nó không thực sự rõ ràng những gì bạn đang cố gắng để thực hiện. Suy nghĩ đầu tiên của tôi là sendError nhưng bạn nói rằng không làm những gì bạn muốn ... bạn đã xem xét việc tạo ra một bộ "phản hồi lỗi", có nghĩa là nội dung xml hoặc JSON cụ thể (hoặc bất kỳ thứ gì bạn đang sử dụng làm ngôn ngữ chuyển giao) chứa thông báo lỗi hoặc mã và bất kỳ thông tin hữu ích nào khác?

Tôi đã làm điều tương tự cho dịch vụ RESTful dựa trên Spring-mvc trong khi trở lại và nó hoạt động tốt nhưng bạn phải nắm bắt và xử lý mọi ngoại lệ để giữ khách hàng không nhận được thông báo 500 chung hay gì đó. Trình giải quyết ngoại lệ mùa xuân hoạt động tốt cho điều đó.

Hy vọng điều này sẽ giúp ... nếu không, có thể rõ ràng hơn một chút về những gì bạn đang cố gắng hoàn thành. Xin lỗi nếu tôi đang dày đặc và thiếu một cái gì đó hiển nhiên.

2

Tôi không quen thuộc với 'các phương pháp hay nhất' xung quanh REST. Nhưng tôi biết khái niệm này dựa trên HTTP và làm thế nào nó được cho là làm việc tự nhiên. Vì vậy, làm thế nào về việc sử dụng một loại mime và văn bản đơn giản bên trong cơ thể cho một lỗi ứng dụng, như 'application/myapp-exception' và một số 'Bla bla'? Bạn có thể cung cấp thư viện khách hàng cho điều đó.

Tôi sẽ không sử dụng mã phản hồi HTTP cho các lỗi ứng dụng. Bởi vì tôi muốn biết những gì không thành công: cho dù đó là ứng dụng của tôi hay máy chủ HTTP của tôi.

(Tôi hy vọng, tôi sẽ thấy một số lời khuyên thực hành tốt nhất ở đây, quá.)

+3

Trong trường hợp đó, không * 403 Forbidden * biểu thị một HTTP Server không thành công hoặc một ứng dụng không thành công? Và những gì về * 418 Tôi là một ấm trà *, như được định nghĩa trong http://www.ietf.org/rfc/rfc2324.txt? ;-) – Arjan

+0

Hehe, điểm tốt. Nhưng tôi đã đề xuất giải pháp này, bởi vì nội dung tiêu đề bị hạn chế. Vì vậy, có, tôi phải sửa bản thân mình. Có quyền sử dụng mã phản hồi để biểu thị lỗi ứng dụng/máy chủ. Nhưng tôi sẽ không gửi thông báo lỗi với tiêu đề, vì những hạn chế (mã hóa, độ dài, vv). Để tự gửi thông báo lỗi, tôi đề xuất sử dụng loại MIME và nội dung phản hồi. Vì vậy, ứng dụng của bạn không phải biết về bất kỳ hạn chế nào, khi tạo thông báo lỗi cho máy khách. – cafebabe

0

Tôi nghĩ rằng sendError nên làm điều đó, nhưng máy chủ ứng dụng của bạn có thể không ... IBM WebSphere 3.5 không thành công trên tôi một thời gian dài trước đây trong khi Tomcat sẽ truyền bá thông điệp tốt; xem JavaServer Pages (JSP) and JSTL - Error page: preserve header "HTTP/1.x 400 My message"? trên diễn đàn Sun.

Cuối cùng tôi đã sử dụng workaround sau, nhưng đây là loại JSP cụ thể, và trong thực tế có thể là cũ:

<%@ page isErrorPage="true" %> 
<% 
    // This attribute is NOT set when calling HttpResponse#setStatus and then 
    // explicitely incuding this error page using RequestDispatcher#include() 
    // So: only set by HttpResponse#sendError() 
    Integer origStatus = 
     (Integer)request.getAttribute("javax.servlet.error.status_code"); 
    if(origStatus != null) { 
     String origMessage = 
      (String)request.getAttribute("javax.servlet.error.message"); 
     if(origMessage != null) { 
      response.reset(); 
      response.setContentType("text/html"); 
      // deprecated, but works: 
      response.setStatus(origStatus.intValue(), origMessage); 
      // would yield recursive error: 
      // response.sendError(origStatus, origMessage); 
     } 
    } 
%> 

Và nếu bạn xảy ra để thử nghiệm với trình duyệt Internet Explorer: "thông báo lỗi Hiện thân thiện HTTP vô hiệu hóa ". (Khi không tắt điều đó, IE có một số yêu cầu kỳ lạ về độ dài tối thiểu của nội dung HTML, nếu không được đáp ứng, sẽ - sẽ làm cho IE hiển thị thông báo lỗi của chính nó. Xem thêm khóa đăng ký HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds tại số Description of Hypertext Transport Protocol Error Messages của Microsoft).

8

Sau khi làm rõ, tôi đã thử tính năng này trong Tomcat.Thực hiện

response.sendError(HttpServletResponse.SC_BAD_REQUEST, "message goes here"); 

lợi nhuận

HTTP/1.1 400 message goes here 

như dòng đầu tiên trong các phản ứng.

Phải có sự cố với vùng chứa servlet bạn đang sử dụng.

+0

Theo tài liệu, sendError chỉ được đảm bảo để gửi tin nhắn trong nội dung. Nó không nói bất cứ điều gì về dòng trạng thái. –

+0

Hmmm, tôi không nhớ thiết lập sendError có bất kỳ nội dung nào không? Tôi đã luôn luôn nghĩ rằng phần máy chủ web sẽ tạo ra một số nội dung mặc định nếu ứng dụng không cung cấp nó. Liên kết bạn cung cấp dường như không đề cập đến điều này? – Arjan

17

Nếu bạn đang sử dụng Tomcat, xem org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER thiết lập:

http://tomcat.apache.org/tomcat-5.5-doc/config/systemprops.html

  • Nếu điều này là đúng HTTP tùy chỉnh thông điệp trạng thái sẽ được sử dụng trong tiêu đề HTTP. Người dùng phải đảm bảo rằng bất kỳ thông điệp nào như vậy được mã hoá ISO-8859-1, đặc biệt nếu người dùng cung cấp đầu vào được bao gồm trong thông báo, để ngăn chặn lỗ hổng XSS có thể xảy ra. Nếu không được chỉ định, giá trị mặc định của false sẽ được sử dụng.

Xem trang này để một số chi tiết về lỗ hổng gốc:

http://www.securityfocus.com/archive/1/archive/1/495021/100/0/threaded

+0

Aha, rất vui được biết! – Arjan

0

Trong ứng dụng web Spring hỗ trợ, chạy trên Tomcat tôi sử dụng sau đậu:

import java.util.Map; 
import java.util.Set; 
import java.util.Map.Entry; 

import org.springframework.beans.factory.InitializingBean; 

public class SystemPropertiesInitializingBean implements InitializingBean { 

    private Map<String, String> systemProperties; 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     if (null == systemProperties || systemProperties.isEmpty()) { 
      return; 
     } 

     final Set<Entry<String, String>> entrySet = systemProperties.entrySet(); 
     for (final Entry<String, String> entry : entrySet) { 

      final String key = entry.getKey(); 
      final String value = entry.getValue(); 

      System.setProperty(key, value); 
     } 

    } 

    public void setSystemProperties(final Map<String, String> systemProperties) { 
     this.systemProperties = systemProperties; 
    } 

} 

Và trong applicationContext .xml:

<bean class="....SystemPropertiesInitializingBean"> 
    <property name="systemProperties"> 
     <map> 
      <entry key="org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER" value="true"/> 
     </map> 
    </property> 
</bean> 
Các vấn đề liên quan