Как правильно отправить HTTP-сообщение клиенту

Я работаю над веб-сервисом RESTful на Java. Мне нужен хороший способ отправлять сообщения об ошибках клиенту, если что-то не так.

СогласноJavadoc, HttpServletResponse.setStatus(int status, String message) устарела"due to ambiguous meaning of the message parameter."

Есть ли предпочтительный способ установить сообщение о статусе или & quot;разумная фраза& Quot; ответа?sendError(int, String) Метод не делает этого.

РЕДАКТИРОВАТЬ: Чтобы уточнить, я хочу изменить строку состояния HTTP, т.е."HTTP/1.1 404 Not Found", а не содержание тела. В частности, я хотел бы отправить ответы, такие как"HTTP/1.1 400 Missing customerNumber parameter".

 Adam Crume09 июл. 2009 г., 01:28
В этом нет ничего особенного, просто я хочу отправить более конкретное сообщение.
 laz09 июл. 2009 г., 00:49
Что-то не так с фразой причины по умолчанию, которую ваш контейнер сервлетов возвращает при использовании sendError?

Ответы на вопрос(7)

Решение Вопроса

что какой-либо клиент RESTful мог бы ожидать, что он посмотрит на фразу причины, чтобы выяснить, что пошло не так; большинство услуг RESTful, которые я видел / использовал, отправляют стандартную информацию о состоянии и расширенное сообщение в теле ответа.sendError(int, String) идеально подходит для такой ситуации.

 Adam Crume09 июл. 2009 г., 16:58
Несколько человек утверждали, что я не должен даже отправлять сообщение с помощью фразы причины, и я полагаю, что я убежден. Я не могу использовать sendError (int, String), потому что контейнер искажает сообщение. Если я вызываю sendError (400, «blah»), тело ответа (по крайней мере, в WebSphere) будет «Ошибка 400: blah». Не хорошо, особенно если вы хотите вернуть XML или другой строгий формат. Я буду вызывать setStatus (int) и вместо этого писать содержимое тела вручную.

чего вы пытаетесь достичь. Моей первой мыслью был sendError, но вы говорите, что не делаете то, что хотите ... рассматривали ли вы создание набора "ответов об ошибках", то есть определенного содержимого XML или JSON (или того, что вы используете в качестве языка передачи) который содержит сообщение об ошибке или код и любую другую полезную информацию?

Некоторое время назад я делал что-то подобное для сервисов RESTful на основе Spring-mvc, и это работало хорошо, но вы должны в значительной степени перехватывать и обрабатывать каждое исключение, чтобы не дать клиенту получить общее сообщение 500 или что-то в этом роде. Резольверы Spring Exception работали хорошо для этого.

Надеюсь, это поможет ... если нет, может быть, немного больше ясности в том, что вы пытаетесь достичь. Извините, если я плотный и упускаю что-то очевидное.

посмотрите настройку org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER:

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://www.securityfocus.com/archive/1/archive/1/495021/100/0/threaded

 09 июл. 2009 г., 09:31
Ага, приятно знать!
 14 июн. 2018 г., 14:52
Обратите внимание, что вышеуказанное системное свойство больше не поддерживается, начиная с tomcat 8.5. Вместо этого теперь есть опция соединителя «sendReasonPhrase» - и это также будет устаревшим с tomcat 9 в пользу соответствия последней спецификации HTTP, которая исключает использование фразы причины. Также смотрите обсуждение здесь:bz.apache.org/bugzilla/show_bug.cgi?id=60362

что концепция основана на HTTP и как он должен работать естественным образом. Так как насчет использования MIME-типа и простого текста внутри тела для ошибки приложения, например «application / myapp-exception» apos; и некоторые "Bla Bla"? Вы можете предоставить клиентскую библиотеку для этого.

Я бы не использовал HTTP-коды ответов для ошибок приложения. Потому что мне нравится знать, что не работает: будь то мое приложение или мой HTTP-сервер.

(Надеюсь, я также увижу здесь советы по передовому опыту.)

 09 июл. 2009 г., 12:38
Хе-хе, хорошая мысль. Но я предложил это решение, потому что содержимое заголовка ограничено. Так что да, я должен исправить себя. Правильно использовать код ответа для обозначения ошибки приложения / сервера. Но я бы не стал отправлять сообщение об ошибке с заголовком из-за ограничений (кодировка, длина и т. Д.). Для отправки самого сообщения об ошибке я предлагаю использовать тип MIME и тело ответа. Таким образом, ваше приложение не должно знать о каких-либо ограничениях при создании сообщения об ошибке для клиента.
 09 июл. 2009 г., 01:30
В этом случае, делает403 Forbidden обозначает сбойный HTTP-сервер или сбойное приложение? И что насчет418 I'm a teapotкак определено вietf.org/rfc/rfc2324.txt ? ;-)

работающем на 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>

sendError должен сделать это, но ваш сервер приложений может не работать ... IBM WebSphere 3.5 давал мне сбой давным-давно, в то время как Tomcat распространял бы сообщение очень хорошо; увидетьСтраницы JavaServer (JSP) и JSTL - страница ошибок: сохранить заголовок "HTTP / 1.x 400 Мое сообщение"? на форумах Солнца.

В конце концов я использовал следующий обходной путь, но это специфично для 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: отключите & quot; Показывать дружественные сообщения об ошибках HTTP & quot; (Если это не отключено, в IE есть какое-то странное требование некоторой минимальной длины содержимого HTML, которое, если не будет выполнено, приведет к тому, что вместо этого IE будет показывать собственное сообщение об ошибке. См. Также раздел реестраHKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds в MicrosoftОписание сообщений об ошибках гипертекстового транспортного протокола.)

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

возвращается

HTTP/1.1 400 message goes here

как первая строка в ответе.

Должна быть проблема с контейнером сервлета, который вы используете.

 09 июл. 2009 г., 01:34
Хммм, я не помню, чтобы sendError устанавливал какой-либо контент? Я всегда думал, что часть веб-сервера будет генерировать некоторый контент по умолчанию, если приложение не предоставит его. Ссылка, которую вы указали, тоже не упоминается?
 Adam Crume09 июл. 2009 г., 01:25
Согласно документации, sendError гарантирует только отправку сообщения в контенте. Он ничего не говорит о строке состояния.

Ваш ответ на вопрос