如何正确地将HTTP消息发送到客户端

时间:2009-07-08 22:26:59

标签: java http java-ee servlets status

我正在使用Java的RESTful Web服务。如果出现问题,我需要一种向客户端发送错误消息的好方法。

根据JavadocHttpServletResponse.setStatus(int status, String message)由于消息参数含义不明确而被弃用“。

是否有首选方式设置状态消息或响应的“reason phrase”? sendError(int, String)方法不会这样做。

编辑: 为了澄清,我想修改HTTP状态行,即"HTTP/1.1 404 Not Found",而不是正文内容。具体来说,我想发送像"HTTP/1.1 400 Missing customerNumber parameter"这样的回复。

7 个答案:

答案 0 :(得分:21)

我认为任何RESTful客户端都不会期望查看出现问题的原因。我见过/使用过的大多数RESTful服务都会在响应正文中发送标准状态信息和扩展消息。 sendError(int, String)非常适合这种情况。

答案 1 :(得分:18)

如果您使用的是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

答案 2 :(得分:12)

在澄清之后,我在Tomcat中尝试了这个。执行

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

返回

HTTP/1.1 400 message goes here

作为回复中的第一行。

您正在使用的servlet容器一定存在问题。

答案 3 :(得分:2)

我不太熟悉REST的“最佳实践”。但我知道这个概念是基于HTTP以及它应该如何自然地解决。那么如何在主体内部使用mime类型和简单文本来解决应用程序错误,例如'application / myapp-exception'和一些'Bla bla'?您可以为此提供客户端库。

我不会将HTTP响应代码用于应用程序错误。因为我想知道什么是失败的:无论是我的应用程序还是我的HTTP服务器。

(我希望,我也会在这里看到一些最佳实践建议。)

答案 4 :(得分:0)

你想要完成的事情并不是很清楚。我的第一个想法是sendError,但是你说它没有做你想要的...你看过创建一组“错误响应”,意思是特定的xml或JSON内容(或者你用作转移语言的任何东西)包含错误消息或代码以及任何其他有用信息?

我曾经为基于Spring-mvc的RESTful服务做了类似的事情,但它运行良好但你必须抓住并处理每个异常,以防止客户端获得通用的500消息或其他东西。 Spring异常解析器在这方面运作良好。

希望这会有所帮助......如果没有,也许可以更清楚地了解你想要实现的目标。对不起,如果我是密集的,并且遗漏了一些明显的东西。

答案 5 :(得分: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对HTML内容的某些最小长度有一些奇怪的要求,如果不满足,将会 - 或者 - 会使IE显示自己的错误消息。另请参阅注册表项HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds at微软的Description of Hypertext Transport Protocol Error Messages。)

答案 6 :(得分:0)

在Spring驱动的Web应用程序中,在Tomcat上运行我使用以下bean:

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>