Установка сообщения об ошибке и тела сервлета

Я хочу написать сервлет, который будет возвращать такой HTTP-ответ:

HTTP/1.1 500 <short custom message>
Content-Length: ...

<longer custom message>

Причина в том, что я хочу, чтобы программный клиент мог обрабатывать ответное сообщение, чтобы получить конкретный ответ, но я также хочу заполнить тело ответа более подробным объяснением, чтобы его было легко использовать с помощью браузера.

Теперь в HttpServletResponse есть метод sendError (int, String), который позволяет мне указать код ошибки и сообщение. В javadocs говорится только о том, что сообщение будет встроено в какую-то html-страницу, но ничего не говорится о настройке сообщения HTTP-ответа. После вызова этого метода вам не разрешается писать в ответ что-либо еще. В моих тестах (с причалом) сообщение используется как для ответа http, так и для тела html, что меня устраивает, за исключением того, что я хочу указать две разные строки, и я не думаю, что настройка ответа http сообщение гарантировано с другой реализацией.

Также существует метод setStatus (int), который вы можете вызвать с любым кодом, а затем вы можете написать свое собственное тело html. Это близко, за исключением того, что вы не можете указать сообщение ответа http.

Наконец, есть метод setStatus (int, String), который действительно делает именно то, что я хочу, но он устарел из-за некоторой двусмысленности. Я предполагаю, что некоторые контейнеры сервлетов записывали сообщение в тело ответа и закрывали ответ.

Помимо использования устаревшего метода, я предполагаю, что я здесь облажался, но мне любопытно, знает ли кто-нибудь еще какие-нибудь уловки?


person Jeremy Huiskamp    schedule 07.10.2010    source источник


Ответы (6)


Также существует метод setStatus (int), который вы можете вызвать с любым кодом, а затем вы можете написать свое собственное тело html. Это близко, за исключением того, что вы не можете указать ответное сообщение http.

Есть ли причина, по которой вы не использовали бы response.setStatus(500) для установки кода состояния HTTP с последующей записью в выходной поток ответа?

Так достигается «запись в тело ответа» на самом низком уровне.

Вот пример:

public class ErrorServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        // 500 error
        resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        resp.getWriter().print("<html><head><title>Oops an error happened!</title></head>");
        resp.getWriter().print("<body>Something bad happened uh-oh!</body>");
        resp.getWriter().println("</html>");
    }
}

web.xml:

<web-app>
    <servlet>
        <servlet-name>myerror</servlet-name>
        <servlet-class>brown.testservlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>myerror</servlet-name>
        <url-pattern>/myErrorPage</url-pattern>
    </servlet-mapping>
</web-app>

И вывод:

$ curl -I http://localhost:8080/testservlet/myErrorPage  
HTTP/1.1 500 Internal Server Error  
Content-Length: 108  
Server: Jetty(6.1.16)  

$ curl -v http://localhost:8080/testservlet/myErrorPage
* About to connect() to localhost port 8080 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /testservlet/myErrorPage HTTP/1.1
> User-Agent: curl/7.20.0 (i686-pc-mingw32) libcurl/7.20.0 OpenSSL/0.9.8k zlib/1.2.3
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 500 Internal Server Error
< Content-Length: 108
< Server: Jetty(6.1.16)
<
<html><head><title>Oops an error happened!</title></head><body>Something bad happened uh-oh!</body></html>
* Connection #0 to host localhost left intact
* Closing connection #0
person matt b    schedule 08.10.2010
comment
Да, в той части моего вопроса, которую вы процитировали, говорится, что я понимаю этот вариант. Он также указывает на то, что это не позволяет вам установить сообщение HTTP-ответа (внутренняя ошибка сервера в вашем примере, которая автоматически предоставляется контейнером сервлета). - person Jeremy Huiskamp; 09.10.2010
comment
Несмотря на то, что response.setStatus(int, String) устарел, вы должны иметь возможность использовать его для установки сообщения строки состояния - person matt b; 09.10.2010

Вы можете настроить страницы ошибок, указав страницы с конкретными ошибками в web.xml:

<error-page>
  <error-code>500</error-code>
  <location>/error500.jsp</location>
</error-page>

В файле jsp вы можете использовать атрибуты запроса для отображения настраиваемого сообщения и другой информации.

person FRotthowe    schedule 07.10.2010
comment
Спасибо, это отличный момент и, вероятно, поможет большинству людей с этой проблемой :) Я использую встроенный причал без настройки всего веб-приложения: это полностью автономный сервлет. Я могу по крайней мере покопаться, чтобы увидеть, можно ли каким-то образом настроить страницу с ошибкой в ​​коде, но я, вероятно, остановлюсь на том, чтобы программные вызывающие программы просто смотрели в теле для деталей. - person Jeremy Huiskamp; 08.10.2010
comment
Просто хотел упомянуть одну оговорку, на которую я наткнулся. Если вы попытаетесь использовать html-страницу вместо jsp, сервер не отправит правильный код состояния, хотя будет отображаться содержимое страницы с ошибкой. - person Asa; 14.05.2012

Если вы хотите, чтобы в заголовках отображалось собственное сообщение об ошибке, почему бы не добавить собственный заголовок с response.addHeader(String, String)? Объединение этого с ответом Мэтта Б. может помочь.

person nash    schedule 07.12.2011

Что ж, извините, самая очевидная причина иметь тело для ответа об ошибке - показать что-то удобочитаемое в браузере при возникновении ошибки. Это причина, по которой создание HTML является поведением sendError по умолчанию в спецификации сервлета.

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

person Juan    schedule 19.07.2012

Используя JBoss 6, я пришел к выводу, что код ответа должен быть установлен после вызова getWriter, чтобы отключить ответ страницы пользовательской ошибки Jboss. Я предполагаю, что реализация предоставляет разных писателей в зависимости от статуса ответа.

response.getWriter().print(message);
response.setStatus(500);
person Elijah    schedule 11.12.2012

Похоже, что все API, предназначенные для установки фразы причины в HTTP, устаревают из-за этого:

RFC 7230, Протокол передачи гипертекста (HTTP / 1.1): синтаксис и маршрутизация сообщений, июнь 2014 г. Раздел 3.1.2:

Элемент «причина-фраза» существует с единственной целью - предоставить текстовое описание, связанное с числовым кодом состояния, в основном из уважения к более ранним протоколам Интернет-приложений, которые чаще использовались с интерактивными текстовыми клиентами. Клиенту СЛЕДУЕТ игнорировать содержание фразы "причина".

Tomcat удалил поддержку свойства org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER в версии 8.5.0.

person Jarekczek    schedule 13.05.2017
comment
Спасибо. На данный момент я уже не помню, почему я хотел, чтобы клиент мог проверить фразу причины, но не похоже, что это была очень хорошая идея. - person Jeremy Huiskamp; 04.09.2017