Java 如何正确地向客户端发送HTTP消息

Java 如何正确地向客户端发送HTTP消息,java,http,jakarta-ee,servlets,status,Java,Http,Jakarta Ee,Servlets,Status,我正在用Java开发一个RESTful web服务。如果出现问题,我需要一种向客户端发送错误消息的好方法 根据http://code>HttpServletResponse.setStatus(int status,String message)被弃用“因为message参数的含义不明确” 是否有设置响应的状态消息或“”的首选方法?sendError(int,String)方法无法执行此操作 编辑: 为了澄清,我想修改HTTP状态行,即“HTTP/1.1 404未找到”,而不是正文内容。具体地说

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

根据http://code>HttpServletResponse.setStatus(int status,String message)被弃用“因为message参数的含义不明确”

是否有设置响应的状态消息或“”的首选方法?
sendError(int,String)
方法无法执行此操作

编辑:
为了澄清,我想修改HTTP状态行,即“HTTP/1.1 404未找到”,而不是正文内容。具体地说,我想发送一些响应,如HTTP/code>“HTTP/1.1400缺少customerNumber参数”

不清楚您想要实现什么。我的第一个想法是sendError,但你说这不符合你的要求。。。您是否考虑过创建一组“错误响应”,即包含错误消息或代码以及任何其他有用信息的特定xml或JSON内容(或您正在使用的任何传输语言)

不久前,我为基于SpringMVC的RESTful服务做了类似的事情,它工作得很好,但您必须捕获并处理每个异常,以防止客户端收到一般的500条消息或其他消息。Spring异常解析器在这方面工作得很好


希望这有助于。。。如果没有,也许你会更清楚地知道你想要实现什么。很抱歉,我太过密集,遗漏了一些明显的东西。

我不太熟悉REST的“最佳实践”。但我知道这个概念是基于HTTP的,它应该是如何自然工作的。那么,对于应用程序错误,比如“application/myappexception”和一些“Bla-Bla”,在正文中使用mime类型和简单文本怎么样?您可以为此提供一个客户端库

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


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

我认为
发送错误应该可以做到这一点,但您的应用程序服务器可能出现故障。。。IBM WebSphere 3.5很久以前在我身上失败了,而Tomcat可以很好地传播消息;请参见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\U LOCAL\u MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds
,位于Microsoft),我在Tomcat上试过这个。执行

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

HTTP/1.1 400 message goes here
作为响应中的第一行


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

我认为任何RESTful客户机都不会期望查看原因短语来找出哪里出了问题;我见过/使用过的大多数RESTful服务都会在响应主体中发送标准状态信息和扩展消息<代码>发送错误(int,String)
非常适合这种情况。

如果您使用的是Tomcat,请参阅标题中的设置org.apache.coyote.USE\u CUSTOM\u STATUS\u MSG\u:

  • 如果这是真的,自定义HTTP状态消息将在HTTP头中使用。用户必须确保任何此类消息都是ISO-8859-1编码的,特别是如果消息中包含用户提供的输入,以防止可能的XSS漏洞。如果未指定,将使用默认值false
有关原始漏洞的详细信息,请参见本页:


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

}
import java.util.Map;
导入java.util.Set;
导入java.util.Map.Entry;
导入org.springframework.beans.factory.initializebean;
公共类SystemPropertieInitializingBean实现初始化Bean{
私有地图系统属性;
@凌驾
public void afterPropertieSet()引发异常{
if(null==systemProperties | | systemProperties.isEmpty()){
返回;
}
final Set entrySet=systemProperties.entrySet();
for(最终条目:entrySet){
最后一个字符串key=entry.getKey();
最终字符串值=entry.getValue();
System.setProperty(键、值);
}
}
公共void集合系统属性(最终映射系统属性){
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>


当您使用sendError时,servlet容器返回的默认原因短语是否有问题?没有什么特别的问题,只是我想发送一条更具体的消息。根据文档,sendError只保证在内容中发送消息。它没有说明任何关于状态行的内容。嗯,我不记得sendError设置了任何内容?我一直认为,如果应用程序不提供web服务器部件,它将生成一些默认内容。您提供的链接似乎也没有提到这一点?我尝试过,通过这种方式设置响应主体,但结果是一个HTML主体,尽管它包含我设置的响应主体。在这种情况下,403禁止是否表示HTTP服务器或应用程序出现故障?那么418“我是一个茶壶”呢?;-)呵呵,说得好。但是我提出了这个解决方案,因为标题内容是有限的。所以,是的,我必须纠正我自己。使用响应代码表示应用程序/服务器错误是正确的。但是我不会发送带有标题的错误消息,因为有一些限制(编码、长度)