2009-07-08 137 views
39

我正在使用Java中的REST風格的Web服務。如果出現問題,我需要一個很好的方法來向客戶端發送錯誤消息。如何正確地向客戶端發送HTTP消息

根據Javadoc,HttpServletResponse.setStatus(int status, String message)已被棄用「由於消息參數含義不明確」。

是否有首選方法來設置響應的狀態消息或「reason phrase」? sendError(int, String)方法不會這樣做。

編輯: 爲了澄清,我想修改HTTP狀態行,即"HTTP/1.1 404 Not Found",而不是正文內容。具體來說,我想發送回覆如"HTTP/1.1 400 Missing customerNumber parameter"

+0

當您使用sendError時,servlet容器返回的默認原因短語是否有問題? – laz 2009-07-08 22:49:56

+0

它沒有什麼特別的錯,只是我想發送一個更具體的消息。 – 2009-07-08 23:28:18

回答

16

我不認爲任何RESTful客戶端會希望看一下原因短語找出什麼地方出了錯;我見過/使用過的大多數RESTful服務都會在響應的主體中發送標準狀態信息和擴展消息。 sendError(int, String)非常適合這種情況。

0

這是不是很清楚你想要完成什麼。我的第一個想法是sendError,但你說這不會做你想做的事......你是否看過創建一組「錯誤響應」,意思是特定的XML或JSON內容(或任何你用作傳輸語言的)包含錯誤消息或代碼以及其他任何有用的信息?

我做了類似於基於Spring-mvc的RESTful服務,而且它運行良好,但是您必須捕獲並處理每個異常,以防止客戶端獲得通用的500消息或其他東西。 Spring Exception Resolvers在這方面效果很好。

希望這有助於......如果沒有,也許你想要完成什麼更清晰一點。對不起,如果我正在密集和失去明顯的東西。

2

我對REST的'最佳實踐'還不是很熟悉。但我知道這個概念是基於HTTP以及它應該如何自然解決。那麼如何在應用程序錯誤中使用MIME類型和簡單文本,如'application/myapp-exception'和一些'Bla bla'?您可以爲此提供一個客戶端庫。

我不會對應用程序錯誤使用HTTP響應代碼。因爲我想知道什麼是失敗的:無論是我的應用程序還是我的HTTP服務器。

(我希望,我會在這裏看到一些最佳實踐建議,也。)

+3

在這種情況下,* 403 Forbidden *表示失敗的HTTP服務器還是失敗的應用程序?那麼* 418我是一個茶壺*,如http://www.ietf.org/rfc/rfc2324.txt中所定義的那樣? ;-) – Arjan 2009-07-08 23:30:06

+0

嘿嘿,好點。但是我提出了這個解決方案,因爲標題內容是有限的。所以是的,我必須糾正自己。使用響應代碼來表示應用程序/服務器錯誤是正確的。但是由於限制(編碼,長度等),我不會將錯誤信息與標題一起發送。爲了發送錯誤消息本身,我建議使用MIME類型和響應主體。因此,在爲客戶端創建錯誤消息時,您的應用程序不必知道任何限制。 – cafebabe 2009-07-09 10:38:11

0

我認爲sendError應該這樣做,但是你的應用服務器可能失敗...的IBM WebSphere 3.5失敗對我的很久以前,Tomcat會很好地傳播信息;請參閱Sun論壇上的JavaServer Pages (JSP) and JSTL - Error page: preserve header "HTTP/1.x 400 My message"?

最後我用以下解決方法,但這是一種JSP具體的,而實際上可能是老:

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

而且如果你碰巧使用Internet Explorer測試:禁用「顯示友好HTTP錯誤信息」。 (當不禁用IE瀏覽器時,IE對HTML內容的某些最小長度有一些奇怪的要求,如果不符合,將會使IE顯示自己的錯誤消息。另請參閱微軟的Description of Hypertext Transport Protocol Error Messages上的註冊表項HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds。)

8

經過澄清之後,我在Tomcat中試了這個。執行

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

返回

HTTP/1.1 400 message goes here 

作爲響應的第一行。

必須有與您正在使用的servlet容器有問題。

+0

根據文檔,sendError只保證在內容中發送消息。它沒有提到任何有關狀態的信息。 – 2009-07-08 23:25:03

17

如果您正在使用Tomcat,請參見設置org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER:

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

  • 如果這是真實的自定義HTTP狀態消息將HTTP頭中使用。用戶必須確保任何此類消息均爲ISO-8859-1編碼,特別是在消息中包含用戶提供的輸入時,以防止可能存在的XSS漏洞。如果未指定,則將使用默認值false。

查看原始漏洞此頁面爲一些細節:

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

0

在動力彈簧的Web應用程序,Tomcat上運行我用以下豆:

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

} 

而在的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> 
相關問題