Отримайте повну URL-адресу та рядок запиту в сервлеті для запитів HTTP та HTTPS


77

Я пишу код, завданням якого є отримання запитаної URL-адреси або повного шляху. Я написав цей код:

HttpServletRequest request;//obtained from other functions
String uri = request.getRequestURI();
if (request.getQueryString() != null)
    uri += "?" + request.getQueryString();

Отже, коли я переглядаю, http://google.com?q=abcце нормально (правильно). Але є проблема, коли я переглядаю https://google.com. Значення uriis http://google.com:443google.com:443, отже, програма застосовується не лише тоді, коли HTTPSвикористовується.

І результат однаковий для request.getRequestURL().toString().

Яке рішення?


3
Я думаю, що, швидше за все, будь-які "інші функції", які ви викликаєте для побудови HttpServletRequest, будують їх неправильно. Можливо, ви можете створити SSCCE, який демонструє точну проблему?
parsifal

Відповіді:


168

За задумом getRequestURL()дає повну URL-адресу, в якій відсутній лише рядок запиту.

В HttpServletRequest, ви можете отримати окремі частини URI , використовуючи методи нижче:

// Example: http://myhost:8080/people?lastname=Fox&age=30

String uri = request.getScheme() + "://" +   // "http" + "://
             request.getServerName() +       // "myhost"
             ":" +                           // ":"
             request.getServerPort() +       // "8080"
             request.getRequestURI() +       // "/people"
             "?" +                           // "?"
             request.getQueryString();       // "lastname=Fox&age=30"
  • .getScheme()дасть вам, "https"якщо це був https://domainзапит.
  • .getServerName()дає domainна http(s)://domain.
  • .getServerPort() дасть вам порт.

Використовуйте фрагмент нижче:

String uri = request.getScheme() + "://" +
             request.getServerName() + 
             ("http".equals(request.getScheme()) && request.getServerPort() == 80 || "https".equals(request.getScheme()) && request.getServerPort() == 443 ? "" : ":" + request.getServerPort() ) +
             request.getRequestURI() +
            (request.getQueryString() != null ? "?" + request.getQueryString() : "");

Цей фрагмент вище отримає повний URI, приховуючи порт, якщо використовувався стандартний, і не додаючи "?"рядок та запит, якщо останній не був наданий.


Запити через проксі

Зверніть увагу, що якщо ваш запит проходить через проксі-сервер, вам потрібно переглянути X-Forwarded-Protoзаголовок, оскільки схема може бути змінена:

request.getHeader("X-Forwarded-Proto")

Крім того, загальним заголовком є X-Forwarded-Forпоказ вихідного IP-запиту замість IP-адреси proxys.

request.getHeader("X-Forwarded-For")

Якщо ви самі відповідаєте за конфігурацію проксі / балансира навантаження, вам потрібно переконатися, що ці заголовки встановлюються під час пересилання.


Ваш перший код допоміг із повторенням, httpsале з помилкою. У запиті немає рядка запитівhttps
progrrammer

вже виправлена ​​та та сама помилка. і так, я пробував getRequestURL ()
progrrammer

@ErBnAcharya getRequestURL() повинен працювати . Здається, ти робиш щось не так ...
informatik01

1
@ErBnAcharya Дуже дивно, що ти отримуєш google.com:443 двічі . Плюс я бачу там http замість https ...
informatik01

1
Я зазначаю @ informatik01 про дивовижність цього. Ось щось, що ви можете зробити: друкувати поштучно, кожен на окремому рядку ( getScheme()в одному getServerName()в іншому), який результат? Це дасть вам підказку щодо проблемної частини.
acdcjunior

9

Просто використовуйте:

String Uri = request.getRequestURL()+"?"+request.getQueryString();

Зверніть увагу, що getRequestURLце не буде працювати на сторінці помилок. Отже, якщо у вас є 404.jspі, наприклад, вам потрібно зробити перенаправлення, вам знадобиться додати import: <%@ page import="org.apache.catalina.util.RequestUtil" %>and useString requestedLocation = RequestUtil.filter((String) request.getAttribute("javax.servlet.error.request_uri"));
Nux

3

Той факт , що HTTPSзапит буде , HTTPколи ви намагалися побудувати URL на стороні сервера вказує на те, що ви могли б мати балансир проксі / навантаження ( nginx, poundі т.д.) розвантаження SSL шифрування перед і вперед до вашого заднього кінця служби в рівнині HTTP.

Якщо це так, перевірте,

  1. чи має ваш проксі налаштований на передніх заголовків правильно ( Host, X-forwarded-proto, X-forwarded-forі т.д.).
  2. чи встановлений ваш службовий контейнер (Напр. Tomcat) для розпізнавання проксі-сервера спереду. Наприклад, Tomcatвимагає додавання secure="true" scheme="https" proxyPort="443"атрибутів до йогоConnector
  3. чи правильно обробляє заголовки ваш код або службовий контейнер. Наприклад, Tomcatавтоматично замінює schemeі remoteAddrт. Д. Значення при додаванні RemoteIpValveдо них Engine. (див. посібник з налаштування , JavaDoc ), тому вам не доведеться обробляти ці заголовки у коді вручну.

Неправильні значення заголовка проксі можуть призвести до неправильного виводу, коли request.getRequestURI()або request.getRequestURL()намагається побудувати вихідну URL-адресу.


Це було вирішення проблеми. Розширюючи це, прочитайте документи про з'єднувач server.xml!
Петер

0

Я знаю, що це питання Java, але якщо ви використовуєте Kotlin, ви можете зробити це досить мило:

val uri = request.run {
    if (queryString.isNullOrBlank()) requestURI else "$requestURI?$queryString"
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.