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

Каков правильный способ установки заголовка Location для ответа HTTP 201 в приложении Java Servlet

Рассмотрим следующий код, отправляющий ответ HTTP 201 "Созданный" клиенту:

    String url = "/app/things?id=42"; // example
    response.setStatus(HttpServletResponse.SC_CREATED);
    response.setContentType("text/plain");
    response.setHeader("Location", url);
    response.getWriter().print(url);

Сообщает клиенту, что была создана новая "вещь" и что ее можно найти по адресу URL /app/things?id=42. Проблема в том, что этот URL является относительным. Это было бы идеально для JSP, который может быть записан следующим образом:

<img src="<c:url value="/things?id=42" />" />

Что создаст следующий HTML:

<img src="/app/things?id=42" />

Это то, что мы хотим для веб-приложений.

Но я не думаю, что это то, что мы хотим для ответного заголовка местоположения 201. Спецификация HTTP указывает:

14.30 Местоположение

Поле заголовка ответа местоположения используется для перенаправления получателя в другое место, кроме Request-URI, для завершения запроса или идентификации нового ресурса. Для ответов 201 (Создано) это местоположение нового ресурса, созданного запросом. Для ответов 3xx местоположение ДОЛЖНО указывать предпочтительный URI сервера для автоматического перенаправления ресурса. Значение поля состоит из одного абсолютного URI.

       Location = "Location" ":" absoluteURI

Пример:

       Location: http://www.w3.org/pub/WWW/People.html

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

Я НЕ считаю, что использование:

request.getServerName() + ":" + request.getServerPort() + url;

Является правильным решением. Должен быть стандартный метод, который дает правильный вывод (чтобы можно было переписать URL-адрес и т.д.). Я не хочу создавать хак.

4b9b3361

Ответ 1

Просто отправьте абсолютный путь. Ограничение на абсолютный URI является известным дефектом в RFC 2616 и будет зафиксировано в HTTPbis (см. http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185).

Обратите внимание, что RFC 7231 теперь включает относительные URI в спецификацию. См. другие ответы, как обрабатывать относительные URIs.

Ответ 2

К сожалению, API сервлета не предоставляет метод, который напрямую возвращает абсолютный URL-адрес до корня контекста. Для этого мне пришлось несколько раз использовать комбинацию getRequestURL(), getRequestURI() и getContextPath().

String absoluteContextRootURL = request.getRequestURL().toString().replace(request.getRequestURI().substring(1), request.getContextPath());

Ответ 3

Решил пойти с советом Юлиана Решке и нарушить спецификацию! По крайней мере, я добавил следующий комментарий:

        /* Note: strictly speaking (per section 14.30 of RFC 2616), the Location header 
         * requires an *absolute URI*. However, in practice, many web 
         * applications send an *absolute path* instead. This is interoperable, 
         * that is, works in popular web browsers  (according to 
         * http://en.wikipedia.org/wiki/HTTP_location).
         * 
         * As the information required to set the Location header to an absolute URI
         * is not generally available to a Servlet, we go with the flow and send
         * an absolute path instead (in violation of RFC 2616).
         * 
         * There is an issue filed with Hypertext Transfer Protocol Bis (httpbis) 
         * working group to resolve this problem here:
         * http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185
         */
        response.setHeader("Location", url);

Причина, по которой я не хочу отправлять абсолютный URI, заключается в том, что я видел проблемы с этим, когда позади балансировщика нагрузки и другой производственной инфраструктуры. Хотя в режиме dev "http://localhost: 8080/foo" работает нормально:))

Будет принимать ответ Джулиана сейчас...

Ответ 4

Если вы используете JAX RS, в javax.ws.rs.core.Response есть метод, который автоматически преобразует относительные URL:

public static Response.ResponseBuilder created(java.net.URI location)

Создайте новый ResponseBuilder для созданного ресурса, установите заголовок местоположения, используя предоставленное значение.

Параметры:

  • location - URI нового ресурса. Если предоставляется относительный URI, он будет преобразован в абсолютный URI, разрешив его относительно URI запроса.

Заметьте, однако, что в реализации JXX RS CXF есть ошибка, которая приводит к неправильным абсолютным URL-адресам.

Ответ 5

Вы можете попробовать

new URL(new URL(request.getRequestURL().toString()), url).toString();

Это, по крайней мере, будет разумным в отношении канонизации любых .. или других странностей. Кроме этого, я не думаю, что это намного лучше, чем манипуляции с строкой.