Подтвердить что ты не робот

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

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

В соответствии с Javadoc, HttpServletResponse.setStatus(int status, String message) устарел "из-за двусмысленного значения параметра сообщения."

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

EDIT: Чтобы уточнить, я хочу изменить строку состояния HTTP, т.е. "HTTP/1.1 404 Not Found", а не содержимое тела. В частности, я бы хотел отправить ответы типа "HTTP/1.1 400 Missing customerNumber parameter".

4b9b3361

Ответ 1

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

Ответ 2

Если вы используете 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

Ответ 3

После вашего разъяснения я попробовал это в Tomcat. Выполнение

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

возвращает

HTTP/1.1 400 message goes here

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

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

Ответ 4

Я не очень хорошо знаком с "лучшими практиками" вокруг REST. Но я знаю, что концепция основана на HTTP и как она должна работать естественным образом. Итак, как насчет использования типа mime и простого текста внутри тела для ошибки приложения, например "application/myapp-exception" и некоторые "Bla bla"? Для этого вы можете предоставить клиентскую библиотеку.

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

(Надеюсь, здесь я также найду советы по лучшей практике.)

Ответ 5

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

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

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

Ответ 6

Я думаю, что sendError должен это сделать, но ваш сервер приложений может терпеть неудачу... IBM WebSphere 3.5 провалился на мне давно, а Tomcat очень хорошо распространял сообщение; см. Страницы JavaServer (JSP) и JSTL - Страница ошибки: сохранить заголовок "HTTP/1.x 400 My message" ? на форумах 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\ErrorThresholds в Microsoft Описание сообщений об ошибках в протоколе гипертекста.)

Ответ 7

В веб-приложении с Spring, запущенным на 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>