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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1100869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:45:46  来源:igfitidea点击:

How to properly send an HTTP message to the client

javahttpjakarta-eeservletsstatus

提问by Adam Crume

I'm working on a RESTful web service in Java. I need a good way to send error messages to the client if something's wrong.

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

According to the Javadoc, HttpServletResponse.setStatus(int status, String message)is deprecated "due to ambiguous meaning of the message parameter."

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

Is there a preferred way to set the status message or "reason phrase" of the response? The sendError(int, String)method doesn't do it.

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

EDIT: To clarify, I want to modify the HTTP status line, i.e. "HTTP/1.1 404 Not Found", not the body content. Specifically, I'd like to send responses like "HTTP/1.1 400 Missing customerNumber parameter".

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

采纳答案by Hank Gay

I don't think any RESTful client would expect to look at the reason phrase to figure out what went wrong; most RESTful services I've seen/used will send the standard status info and an expanded message in the body of the response. sendError(int, String)is ideal for that situation.

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

回答by cjstehno

It's not really clear what you are trying to accomplish. My first thought was the sendError but you say that does not do what you want... have you looked at creating a set of "error responses", meaning specific xml or JSON content (or whatever you are using as a transfer language) that contains the error message or code and any other useful information?

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

I did something like that for Spring-mvc based RESTful services a while back and it worked well but you have to pretty much catch and handle every exception to keep the client from getting a generic 500 message or something. The Spring Exception Resolvers worked well for that.

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

Hope this helps... if not, maybe a little more clarity on what you are trying to accomplish. Sorry if I am being dense and missing something obvious.

希望这会有所帮助......如果没有,也许更清楚你想要完成的事情。对不起,如果我很密集并且遗漏了一些明显的东西。

回答by cafebabe

I'm not quite familiar with the 'best practices' around REST. But I know the concept is based on HTTP and how it is supposed to work out naturally. So how about using a mime type and simple text inside the body for an application error, like 'application/myapp-exception' and some 'Bla bla'? You can provide a client library for that.

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

I would not use HTTP response codes for application errors. Because I like to know what's failing: whether it is my application or my HTTP server.

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

(I hope, I'll see some best practice advices here, too.)

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

回答by Arjan

I think the sendErrorshould do it, but your application server may be failing... IBM WebSphere 3.5 failed on me a long time ago while Tomcat would propagate the message just fine; see JavaServer Pages (JSP) and JSTL - Error page: preserve header "HTTP/1.x 400 My message"?on the Sun forums.

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

Eventually I used the following workaround, but this is kind of JSP specific, and may in fact be old:

最终我使用了以下解决方法,但这是特定于 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); 
        }
    }
%>

And if you happen to test with Internet Explorer: disable "Show friendly HTTP error messages". (When not disabling that, IE has some odd requirement of some minimum length of the HTML content which, if not met, would —or will— make IE show its own error message instead. See also the registry key HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholdsat Microsoft's Description of Hypertext Transport Protocol Error Messages.)

如果您碰巧使用 Internet Explorer 进行测试:禁用“显示友好的 HTTP 错误消息”。(当不禁用它时,IE 对 HTML 内容的最小长度有一些奇怪的要求,如果不满足,将 - 或将 - 使 IE 显示自己的错误消息。另请参阅HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholdsMicrosoft 的超文本传输​​描述中的注册表项协议错误消息。)

回答by laz

After your clarification, I tried this in Tomcat. Executing

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

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

returns

返回

HTTP/1.1 400 message goes here

as the first line in the response.

作为响应中的第一行。

There must be a problem with the servlet container you are using.

你使用的servlet容器肯定有问题。

回答by ars

If you're using Tomcat, see the setting org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER:

如果您使用 Tomcat,请参阅设置 org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER:

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

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

  • If this is true custom HTTP status messages will be used within HTTP headers. Users must ensure that any such message is ISO-8859-1 encoded, particularly if user provided input is included in the message, to prevent a possible XSS vulnerability. If not specified the default value of false will be used.
  • 如果这是真的,则将在 HTTP 标头中使用自定义 HTTP 状态消息。用户必须确保任何此类消息都是 ISO-8859-1 编码的,特别是如果消息中包含用户提供的输入,以防止可能的 XSS 漏洞。如果未指定,将使用默认值 false。

See this page for some detail on the original vulnerability:

有关原始漏洞的一些详细信息,请参阅此页面:

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

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

回答by Illarion Kovalchuk

In Spring powered web application, running on Tomcat I use following bean:

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

}

And in applicationContext.xml:

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