47

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

根据Javadoc“由于 message 参数的含义不明确”而HttpServletResponse.setStatus(int status, String message)被弃用。

是否有首选方法来设置响应的状态消息或“原因短语”?该sendError(int, String)方法不这样做。

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

4

7 回答 7

24

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

于 2009-07-08T23:38:24.743 回答
20

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

于 2009-07-09T00:58:05.367 回答
13

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

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

返回

HTTP/1.1 400 message goes here

作为响应的第一行。

您使用的 servlet 容器一定有问题。

于 2009-07-08T23:12:54.220 回答
2

我对围绕 REST 的“最佳实践”不太熟悉。但我知道这个概念是基于 HTTP 的,并且它应该如何自然地发挥作用。那么如何在正文中使用 mime 类型和简单文本来处理应用程序错误,例如“application/myapp-exception”和一些“Bla bla”?您可以为此提供一个客户端库。

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

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

于 2009-07-08T22:45:26.270 回答
0

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

不久前,我为基于 Spring-mvc 的 RESTful 服务做了类似的事情,它运行良好,但您必须捕获并处理每个异常,以防止客户端收到通用的 500 消息或其他东西。Spring Exception Resolvers 很好地解决了这个问题。

希望这会有所帮助……如果没有,也许可以更清楚地说明您要完成的工作。对不起,如果我很密集并且遗漏了一些明显的东西。

于 2009-07-08T22:37:26.567 回答
0

我认为sendError应该这样做,但是您的应用程序服务器可能会失败... IBM WebSphere 3.5 很久以前在我身上失败了,而 Tomcat 会很好地传播消息;请参阅JavaServer Pages (JSP) 和 JSTL - 错误页面:保留标头“HTTP/1.x 400 我的消息”?在 Sun 论坛上。

最终我使用了以下解决方法,但这是特定于 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\ErrorThresholdsMicrosoft 的超文本传输​​说明中的注册表项协议错误消息。)

于 2009-07-08T23:08:33.510 回答
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>
于 2010-04-27T11:46:15.483 回答