Abrufen der vollständigen URL und Abfragezeichenfolge in Servlet für HTTP- und HTTPS-Anforderungen

77

Ich schreibe einen Code, dessen Aufgabe es ist, eine angeforderte URL oder einen vollständigen Pfad abzurufen. Ich habe diesen Code geschrieben:

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

Wenn ich also surfe http://google.com?q=abc, ist es OK (richtig). Aber es gibt ein Problem beim Stöbern https://google.com. Der Wert von uriist http://google.com:443google.com:443, also das Programm nicht nur, wenn HTTPSes verwendet wird.

Und die Ausgabe ist die gleiche für request.getRequestURL().toString().

Was ist die Lösung?

Programmierer
quelle
3
Ich denke, es ist höchstwahrscheinlich, dass alle "anderen Funktionen", die Sie zum Konstruieren aufrufen, HttpServletRequestdiese falsch konstruieren. Vielleicht können Sie eine SSCCE erstellen , die das genaue Problem demonstriert?
Parsifal

Antworten:

168

Mit dem Design, getRequestURL()gibt Ihnen die vollständige URL, nur die Abfragezeichenfolge fehlt.

In HttpServletRequestkönnen Sie einzelne Teile des URI mit den folgenden Methoden abrufen:

// 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()wird Ihnen geben, "https"wenn es eine https://domainAnfrage war.
  • .getServerName()gibt domainauf http(s)://domain.
  • .getServerPort() wird Ihnen den Hafen geben.

Verwenden Sie das folgende Snippet:

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() : "");

In diesem obigen Snippet wird der vollständige URI abgerufen, wobei der Port ausgeblendet wird, wenn der Standard-URI verwendet wurde, und der "?"und die Abfragezeichenfolge nicht hinzugefügt werden, wenn letzterer nicht angegeben wurde.


Proxied Anfragen

Beachten Sie, dass Sie sich den X-Forwarded-ProtoHeader ansehen müssen, wenn Ihre Anforderung einen Proxy durchläuft, da das Schema möglicherweise geändert wird:

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

Es gibt auch einen allgemeinen Header X-Forwarded-For, der die ursprüngliche Anforderungs-IP anstelle der Proxy-IP anzeigt.

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

Wenn Sie selbst für die Konfiguration des Proxy- / Load-Balancers verantwortlich sind, müssen Sie sicherstellen, dass diese Header bei der Weiterleitung festgelegt werden.

acdcjunior
quelle
Ihr erster Code half bei der Wiederholung, httpsaber mit Fehler. Es gibt keine Abfrage - String inhttps
progrrammer
bereits korrigiert und gleicher Fehler. und ja, ich habe versucht, getRequestURL ()
Programmierer
@ErBnAcharya getRequestURL() muss funktionieren . Scheint, als ob du etwas falsch machst ...
informatik01
1
@ErBnAcharya Es ist sehr seltsam, dass Sie google.com:443 zweimal bekommen . Außerdem sehe ich dort http statt https ...
informatik01
1
Ich habe @ informatik01 über die Seltsamkeit dieses zweiten. Folgendes können Sie tun: Stück für Stück in einer separaten Zeile ( getScheme()in einer getServerName()in der anderen) drucken. Was ist das Ergebnis? Dies gibt Ihnen einen Hinweis darauf, was der problematische Teil ist.
acdcjunior
9

Einfach verwenden:

String Uri = request.getRequestURL()+"?"+request.getQueryString();
sumitkanoje
quelle
Beachten Sie, dass getRequestURLdies auf einer Fehlerseite nicht funktioniert. Wenn Sie also eine 404.jspund z. B. eine Umleitung durchführen müssen, müssen Sie den Import hinzufügen: <%@ page import="org.apache.catalina.util.RequestUtil" %>und verwendenString requestedLocation = RequestUtil.filter((String) request.getAttribute("javax.servlet.error.request_uri"));
Nux
3

Die Tatsache , dass eine HTTPSAnfrage wird , HTTPwenn man versucht , die URL auf Server - Seite zu konstruieren , zeigt an, dass Sie einen Proxy / Load - Balancer haben könnte ( nginx, poundusw.) Offloading SSL - Verschlüsselung vor und freuen uns auf Ihren Back - End - Service in Ebene HTTP.

Wenn dies der Fall ist, überprüfen Sie,

  1. ob Ihre Proxy richtig vorwärts Header eingerichtet wurde ( Host, X-forwarded-proto, X-forwarded-for, usw.).
  2. ob Ihr Service-Container (zB Tomcat) so eingerichtet ist, dass er den Proxy vor sich erkennt. Zum Beispiel Tomcaterfordert das Hinzufügen von secure="true" scheme="https" proxyPort="443"Attributen zu seinerConnector
  3. ob Ihr Code oder Service-Container die Header korrekt verarbeitet. Zum Beispiel Tomcatersetzt automatisch scheme, remoteAddrusw. Werte , wenn Sie hinzufügen , RemoteIpValveum seine Engine. (siehe Konfigurationshandbuch , JavaDoc ), damit Sie diese Header in Ihrem Code nicht manuell verarbeiten müssen.

Falsche Proxy Headerwerte in falscher Ausgabe führen, wenn request.getRequestURI()oder request.getRequestURL()Versuche , den Ursprung URL zu konstruieren.

dancnfoo
quelle
Dies war die Lösung des Problems. Die Ausweitung dieses, lesen Sie die server.xml - Connector - Dokumentation!
Peterh
0

Ich weiß, dass dies eine Java-Frage ist, aber wenn Sie Kotlin verwenden, können Sie dies ganz gut tun:

val uri = request.run {
    if (queryString.isNullOrBlank()) requestURI else "$requestURI?$queryString"
}
Adam Millerchip
quelle