82

I am writing a code which task is to retrieve a requested URL or full path. I've written this code:

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

So, when I browse http://google.com?q=abc it is OK (correct). But there is problem when I browse https://google.com. The value of uri is http://google.com:443google.com:443, So the program doesn't only when HTTPS is used.

And the output is same for request.getRequestURL().toString().

What is the solution?

divanov
  • 6,173
  • 3
  • 32
  • 51
progrrammer
  • 4,475
  • 2
  • 30
  • 38
  • 3
    I think it's most likely that whatever "other functions" that you call to construct the `HttpServletRequest` are constructing it incorrectly. Perhaps you can create a [SSCCE](http://sscce.org/) that demonstrates the exact problem? – parsifal May 21 '13 at 16:48

5 Answers5

182

By design, getRequestURL() gives you the full URL, missing only the query string.

In HttpServletRequest, you can get individual parts of the URI using the methods below:

// 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() will give you "https" if it was a https://domain request.
  • .getServerName() gives domain on http(s)://domain.
  • .getServerPort() will give you the port.

Use the snippet below:

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

This snippet above will get the full URI, hiding the port if the default one was used, and not adding the "?" and the query string if the latter was not provided.


Proxied requests

Note, that if your request passes through a proxy, you need to look at the X-Forwarded-Proto header since the scheme might be altered:

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

Also, a common header is X-Forwarded-For, which show the original request IP instead of the proxys IP.

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

If you are responsible for the configuration of the proxy/load balancer yourself, you need to ensure that these headers are set upon forwarding.

Community
  • 1
  • 1
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
10

Simply Use:

String Uri = request.getRequestURL()+"?"+request.getQueryString();
Community
  • 1
  • 1
sumitkanoje
  • 1,217
  • 14
  • 22
  • Note that `getRequestURL` will not work on an error page. So if you have a `404.jsp` and e.g. need to do a redirect you will need add import: `<%@ page import="org.apache.catalina.util.RequestUtil" %>` and use `String requestedLocation = RequestUtil.filter((String) request.getAttribute("javax.servlet.error.request_uri"));` – Nux Feb 23 '18 at 13:31
4

The fact that a HTTPS request becomes HTTP when you tried to construct the URL on server side indicates that you might have a proxy/load balancer (nginx, pound, etc.) offloading SSL encryption in front and forward to your back end service in plain HTTP.

If that's case, check,

  1. whether your proxy has been set up to forward headers correctly (Host, X-forwarded-proto, X-forwarded-for, etc).
  2. whether your service container (E.g. Tomcat) is set up to recognize the proxy in front. For example, Tomcat requires adding secure="true" scheme="https" proxyPort="443" attributes to its Connector
  3. whether your code, or service container is processing the headers correctly. For example, Tomcat automatically replaces scheme, remoteAddr, etc. values when you add RemoteIpValve to its Engine. (see Configuration guide, JavaDoc) so you don't have to process these headers in your code manually.

Incorrect proxy header values could result in incorrect output when request.getRequestURI() or request.getRequestURL() attempts to construct the originating URL.

dancnfoo
  • 380
  • 2
  • 6
  • This was the solution of the problem. Extending this, [read the server.xml Connector docs!](https://tomcat.apache.org/tomcat-8.0-doc/config/http.html) – peterh May 29 '18 at 14:56
2

I know this is a Java question, but if you're using Kotlin you can do this quite nicely:

val uri = request.run {
    if (queryString.isNullOrBlank()) requestURI else "$requestURI?$queryString"
}
Adam Millerchip
  • 20,844
  • 5
  • 51
  • 74
0

For Spring users, ServletUriComponentsBuilder handles this.

// autowire HttpServletRequest to use here
String fullURL = ServletUriComponentsBuilder.fromRequest(request).build().toString();
// or use current request
String fullURL = ServletUriComponentsBuilder.fromCurrentRequest().build().toString();
Unmitigated
  • 76,500
  • 11
  • 62
  • 80