22

Sometimes you need to construct a full URL to your web app context inside a servlet/JSP/whatever based on HttpServletRequest. Something like http://server.name:8080/context/. Servlet API doesn't have a single method to achieve this.

The straightforward approach is to append all URL components to a StringBuffer, like

ctxUrl = sb.append(req.getScheme()).append("://")
.append(req.getgetServerName()).append(":")
.append(req.getServerPort()) etc

I wonder if there's anything wrong with this alternative (which is 10 times faster):

ctxUrl = req.getRequestURL();
ctxUrl = ctxUrl.substring(0, ctxUrl.lastIndexOf("/")));

Will two above methods always produce the same result?

Oleg Mikheev
  • 17,186
  • 14
  • 73
  • 95
  • 1
    If your URL contains a fragment part, in which slashes are valid, then you have a problem – fge Jan 10 '13 at 02:05

3 Answers3

27

It's called the "base URL" (the one you could use in HTML <base> tag). You can obtain it as follows:

StringBuffer url = req.getRequestURL();
String uri = req.getRequestURI();
String ctx = req.getContextPath();
String base = url.substring(0, url.length() - uri.length() + ctx.length()) + "/";

Your ctxUrl.substring(0, ctxUrl.lastIndexOf("/"))); approach will fail on URLs with multiple folders like http://server.name:8080/context/folder1/folder2/folder3.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • the only issue is that StringBuffer's `substring` returns String which doesn't have `append` method – Oleg Mikheev Jan 10 '13 at 02:22
  • Fixed. Sorry, just typed from top of head and SO editor didn't perform compile checks. – BalusC Jan 10 '13 at 02:24
  • and `+1` to substring's second argument rather than String concatenation could be a better idea, unless there is some other use case that I don't see :) – Oleg Mikheev Jan 10 '13 at 02:28
17

The following will get the context URL and resolve things appropriately.

URI contextUrl = URI.create(req.getRequestURL().toString()).resolve(req.getContextPath());

This will do all the necessary processing for ports, slashes and what not. It will also work for the root context as req.getContextPath() will return ""

If you are using a proxy server you need to ensure that the original Host: request is passed in (e.g. Apache ProxyPass instructions to ProxyPreserveHost.

Community
  • 1
  • 1
Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265
  • 1
    This one didn't work for me. To be precise, it worked fine when my path was http://localhost:port/app-name/module/page, but it didn't work when I put it in beta and the path was https://subdomain.domain.com/module/page. It left the module on in that case. So use wisely, and if your distribution url structure is different then your development url structure, you may want to try something else. – Guy Schalnat Jun 10 '16 at 15:40
  • It worked for me when I accessed the page from app server. But, when I accessed it from from webserver it generated app server url. – Vinod Jun 14 '16 at 09:52
  • If you are using Apache as a proxy you should enable `ProxyPreserveHost` http://stackoverflow.com/a/6101477/242042 – Archimedes Trajano Sep 03 '16 at 22:27
2

Suppose,

We want to get http://server.name:8080/context/ from anywhere in Java web app project.

String uri = request.getRequestURI();
//uri = "/context/someAction"
String url = request.getRequestURL().toString();
// url = "http://server.name:8080/context/someAction"
String ctxPath = request.getContextPath();
// ctxPath = "/context";
url = url.replaceFirst(uri, "");
// url = "http://server.name:8080"
url = url + ctxPath;
//url = "http://server.name:8080/context"

using this code block, we can get the URL

mhmuftee
  • 121
  • 1
  • 6