Как правильно отправить HTTP-сообщение клиенту - PullRequest
41 голосов
/ 09 июля 2009

Я работаю над веб-сервисом 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".

Ответы [ 7 ]

21 голосов
/ 09 июля 2009

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

18 голосов
/ 09 июля 2009

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

12 голосов
/ 09 июля 2009

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

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

возвращает

HTTP/1.1 400 message goes here

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

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

2 голосов
/ 09 июля 2009

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

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

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

0 голосов
/ 27 апреля 2010

В веб-приложении на базе Spring, работающем на Tomcat, я использую следующий компонент:

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>
0 голосов
/ 09 июля 2009

Я думаю, что sendError должен сделать это, но ваш сервер приложений может работать с ошибками ... IBM WebSphere 3.5 давал мне сбой давным-давно, в то время как Tomcat хорошо передавал сообщение; см. Страницы JavaServer (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\ErrorThresholds в Microsoft Описание сообщений об ошибках гипертекстового транспортного протокола .)

0 голосов
/ 09 июля 2009

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

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

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

...