In my application every link generated is surrounded by response.ecodeURL. On some servers encodeURL adds the context-path to the URL.
The application is named "appl". Creating a link /a/b/c.jsp creates on DEV-system the url /a/b/c.jsp, on Prod it creates /appl/a/b/c.jsp
The tomcat is behind an Apache Webserver which connects via ajp, not sure if thats a relevant fact.
EDIT:
The Webserver isn't relevant. I tried going directly on port 8080 and the same happend again.
<c:url> always pre-pends the context path to URLs: this is standard practice and should always be done. If you are using <c:url> then you shouldn't add your own prefix. Also note that <c:url> runs the URL through HttpServletResponse.encodeURL for you. That method adds URL-based session-tracking information (e.g. the ";jsessionid" path parameter) if appropriate.
You should always add the context prefix to all URLs, whether you use something like <c:url> or do it yourself. You just shouldn't do both. When you use the ROOT context, the context path with be "" (i.e. empty string) and nothing will be pre-pended to your URLs.
Related
So here is my story.
I am developing a spring web application. The reloading of static content (js, css, jsp) was broken and found a solution in the following thread:
Getting resources in VFrabric Server to deploy without causing container to reload
In order for reloading to work I couldn't have the root URL '/'. So I change that to '/project' and my reloading works. Great!
But then comes the next problem. I have a lot ajax requests to '/typeahead/searchUniversities/%QUERY' for example, this would need to be changed to 'project/typeahead/searchUniversities/%QUERY'. And when I upload it to the production server I would need to change it back to '/typeahead/searchUniversities/%QUERY'
Since '/project' is just for development
So the I read about profiles but I'm not sure if this is the way to go. I might overdoing it?
I was also thinking of having something like '${baseurl}/typeahead/searchUniversities/%QUERY' and then just change in one place before production. But not sure how to do this.
If someone could guide me with an example of how to do this it would be great.
Thank you!
Edit : add another more direct way to get the context path in a JSP
The url should never be static in the webapp : the context path is determined at deployment time and not at compile time. If you are using spring tag library, you can make use of <spring:url> tag, if not of the JSTL <c:url> tag. Both will automatically add the context path for you.
BTW : in a JSP <%= application.getContextPath() %> gives the context path without any additional taglib.
But please only use relative paths where it has sense and never for "top level" URLs.
Your application shouldn't depend on the context path it is deployed under. One solution to this particular issue would be to use relative paths in your ajax requests,
e.g.
'typeahead/searchUniversities/%QUERY' rather than '/typeahead/searchUniversities/%QUERY'
I'd like to have Tomcat automatically add a trailing slash to my app's context if the url is entered without it.
When I test with Jetty, it automatically adds the trailing slash to my app's context, but Tomcat doesn't do this.
I'm uncertain what the context will be named once deployed, as I'm handing the WAR off to someone else, so any resource references in HTML is all relative. Is there any way to have Tomcat automatically redirect to the same context with a trailing slash added?
Currently Using Tomcat 7 with Spring 3.
It's an old post, but as of Tomcat 7.0.67, you need to add the following attribute to your context.xml file:
<Context mapperContextRootRedirectEnabled="true">...</Context>
As per the 7.0.67 changelog:
Move the functionality that provides redirects for context roots and directories where a trailing / is added from the Mapper to the DefaultServlet. This enables such requests to be processed by any configured Valves and Filters before the redirect is made. This behaviour is configurable via the mapperContextRootRedirectEnabled and mapperDirectoryRedirectEnabled attributes of the Context which may be used to restore the previous behaviour.
And in the Tomcat context documentation:
mapperContextRootRedirectEnabled: If enabled, requests for a web application context root will be redirected (adding a trailing slash) if necessary by the Mapper rather than the default Servlet. This is more efficient but has the side effect of confirming that the context path exists. If not specified, the default value of false is used.
It seems that your application's web.xml has a mapping to "/*". A servlet-mapping to "/*" causes tomcat to pass the request as-is to the web application (i.e. does not redirect).
To properly redirect, you must change the "/*" mapping to just "/", the latter means the default servlet.
Tomcat adds a trailing slash automatically. Just test it with the example application supplied with Tomcat..
If - due to some special configuration - it does not, I'd write a Filter that examines the query string and redirects as needed by the application. Many times this is needed anyways (doing http->https redirections, etc.)
Have you tried playing with URL Rewrite on Tomcat?
This might help: http://code.google.com/p/urlrewritefilter/
If that does not help, take a look at this: URL rewrite in tomcat web.xml
Pat's excellent answer helped me dig up a few more details on this. It seems this is related to some quirks in some versions of Tomcat (Tomcat 7 at 7.0.67+, and Tomcat 8 between 8.29 and 8.37) having to do with session cookies and URL redirection.
The bottom line seems to be that if the java server creates path-specific session cookies with a slash at the end (like "/app_name/"), then the server must also do an automatic initial redirect (/app_name --> /app_name/) ... otherwise, the session cookie will not get sent with the request, and it will never look to the server like you have a valid session. The may cause a redirect loop from the app to the authentication.
There are configurations in Tomcat that control both behaviors, but as far as I can tell, they were essentially out-of-sync in these versions, such that one might get the cookie with the trailing slash, without getting the redirect. There are several related issues/changes in the Tomcat changelog:
https://tomcat.apache.org/tomcat-8.0-doc/changelog.html
As Pat has already noted, this is resolved by adding this attribute to your app's Context element:
<Context mapperContextRootRedirectEnabled="true">
My old way using mod_jk in apache and configure virtual host in tomcat
In the JSP file, I refer to CSS as below
/<%=request.getContextPath()%>/css/styles.css
while the home link is set to
/<%=request.getContextPath()%>/
so this worked fine when I use mod_jk in apache to work with tomcat using ajp;
When I try to configure reverse proxy as below
ProxyPass / http://localhost:800/mywebapp
ProxyPassReverse / http://localhost:800/mywebapp
the home page can be retrieved fine but the css request becomes
http://mydomain.com/mywebapp/mywebapp/css/style.css
so the css file can not be retrieved correctly;
I think one possible way is to always use relative path like ./style.css or ../style.css
a. since header/footer are shared, and the home page is in a different level with detail page, it's inconvenient to use relative path because they're at a different level
b. still, I think the home link will have to be /<%=request.getContextPath()%>/
so I wonder what's the way to set contextroot fine in java web and also work fine with reverse proxy?
thx a lot
As I know your application server (Tomcat) isn't able to be aware of a reverse proxy presence. Generally speaking, it can be contacted through any number of reverse proxies or directly by browsers. A network configuration is usually used to limit this, not HTTP or Java.
So, you must accurately rely on relative URLs to make your application work well.
When I have to deal with reverse proxy presence (almost always due to SSO architectures), I embed a "junction" configuration string item (the portion of the URL used in the proxy to map the application) and use it in the only places where I need to build an absolute URL.
I have 2 tomcat instances. both are behind proxying apache httpds. my code in the Spring controller looks like this:
#RequestMapping(value = "/doSuperSexyStuff", method = RequestMethod.GET)
public String viewSuperSexyStuff() {
return "redirect:/mySuperSexyStuff";
}
On my first tomcat installation on Windows I have somedomain1.dev redirected to http://localhost:8080/myapp and everything works flawlessly. redirect goes to http://somedomain1.dev/mySuperSexyStuff
On the other tomcat installation (which is on Linux) the redirect works relative to the context path and user end up at http://somedomain2.dev/myapp/mySuperSexyStuff which is obviously wrong.
What should I do for spring to ignore the context path and just redirect the user to where he "belongs"?
All URLs in my application are absolute(everything including links in jsps, redirect urls and all the places where links are used). I guess that's not the correct way to do stuff: if I have to implement HTTPS version of the site I'll be in trouble. So if you you think I must change something fundamentally in my approach please point me in the right direction.
Instead of returning a String, which is very inflexible, consider returning a View:
#RequestMapping(value = "/doSuperSexyStuff", method = RequestMethod.GET)
public View viewSuperSexyStuff(){
return new RedirectView("/mySuperSexyStuff");
}
The redirect view has a constructor which takes a boolean contextRelative so the following would do the opposite of the above:
return new RedirectView("/mySuperSexyStuff", true);
All your url's should be context relative unless you really them point off your site, so links to css, image assets etc. should in jsp's use <c:url /> tags to resolve paths.
One of the ways you can achieve this is to use your web application deployed to the root and not as context "myapp". This makes sense as you have separate domains configured. Just use put all your files on the tomcat root folder.
Spring documentation for MVC says that the path sould always be relative to your context path.
As far as I see you have two options:
Using an absolute path in your redirect like "http://somedomain...."
Check your configuration of the context path of the web application
Hope this helps a step further...
I have a web application, which was designed and always worked under root context ("/"). So all css, js and links started with / (for example /css/style.css). Now I need to move this web application to some different context (let's say /app1). It is easy to change server.xml configuration file and bring up web application in new context app1 using [Context path=""] item. But web pages are broken because all links are now incorrect. They point to old root context /css/style.css instead of new app1 context.
Is there any magic way to fix this problem without fixing each link by prefixing with some "context" variable?
Used server - Tomcat 5. Application is written with Java and uses JSP, Struts2, Spring and UrlRewrite filter. More interesting is to hear real experience in fighting with such problems that theoretical debates.
Thank you.
P.S. I do not see how UrlRewrite filter can help me because it will work only in app1 context. So requests to links like /css/style.css will not be passed to it.
If you use URL rewriting to redirect ROOT to your application, won't that eliminate the ability to have a an application in ROOT? If so, what is gained by switching the context?
I think the general way to link resources is to either append a "context" variable and make the link absolute: ${pagecontext.request.contextpath}/css/style.css or just make the link relative: css/style.css
Unless you have specific reasons for being unable to modify the code, I would do a search/replace on the links and be done with it. You should have no more than three or four expressions to find, /css, /images, /javascript, etc.
You should always create urls via url re-writing, not only so that session info can be added to the url, if required, but also so that the context path can be added. You should create all urls as absolutely paths from the top of the application and then let url-rewriting handle adding the context-path to the front, as appropriate.
<c:url value="/css/site.css"/>
That will render /<context-path>/css/site.css or /<context-path>/css/site.css;jsessionid=134345434543 into a jsp file if they don't have cookies enabled. You can also use the c:url tag to render the url into a variable and then use that variable multiple times throughout your document. Just add a var="x" attribute to the tag and then ${x} will render the url into your doc. If you aren't using jsp to render your output, you'll need to find the appropriate mechanism for your view layer, but they will all have one. If you are rendering a url in java code, just take a look at the source code to the c:url tag and you'll see how it is done.
The one awkwardness is that CSS files (and js files) aren't processed, so urls in css and js files need to be relative paths or they will break whenever you change the context path. Most js already uses relative paths since library maintainers don't know what path you are going to install their library to. CSS backround images, on the other hand, are often specified as absolute urls, since the same CSS file may be included into html files at different levels of a file hierarchy. There is no easy fix for this that I am aware of other than to create appropriate symlinks such that the relative url always works or else serve up the problem CSS files via a JSP so that the urls can be rewritten as appropriate. I'm sure there are probably filters or apache modules you can run which will do the url replacement, but then you've still got to manually update your filter/module whenever you deploy to a new context path.