83

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?

1
  • 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 that demonstrates the exact problem? Commented May 21, 2013 at 16:48

5 Answers 5

183

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.

Sign up to request clarification or add additional context in comments.

15 Comments

Your first code helped with repetition in https but with error. There is no query string in https
already corrected and same error. and yes i've tried getRequestURL()
@ErBnAcharya getRequestURL() must work. Seems like you're doing something wrong...
@ErBnAcharya It's very strange that you get google.com:443 twice. Plus I see there http instead of https...
I second @informatik01 on the strangeness of this. Here's something you can do: print piece by piece, each on a separate line (getScheme() in one getServerName() in other), what's the result? This will give you a hint about what's the problematic part.
|
10

Simply Use:

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

1 Comment

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"));
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.

1 Comment

This was the solution of the problem. Extending this, read the server.xml Connector docs!
3

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"
}

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.