How to redirect URLs with trailing slash to the corresponding ones without it?

24,704

Solution 1

You could list all the rewrite rules you need in your web configuration

If there aren't many of those, you can configure redirect views like this

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
    registry.addRedirectViewController("/my/path/", "/my/path")
      .setKeepQueryParams(true)
      .setStatusCode(HttpStatus.PERMANENT_REDIRECT); 
}

Or you could create a custom HandlerInterceptor

But interceptors occur before requests are mapped to a specific Controller.action and you've got no way of knowing Controllers and actions in that context.

All you've got is HTTPServlet API and request+response; so you can:

response.sendRedirect("http://example.org/whitout-trailing-slash");

The answer you don't want to read

This behavior (URL with trailing slash = URL without it) is perfectly "valid" when considering HTTP. At least this is the default behavior with Spring, that you can disable with useTrailingSlashMatch (see javadoc).

So using rewrite/redirect rules on the front-end server could a solution; but again, I don't know your constraints (maybe you could elaborate on this and we could figure out other solutions?).

Solution 2

I think you best option would be to do this before entering in Spring web's servlet, using UrlRewriteFilter. This will ensure that your redirect rules would not impact your controllers.

Please note that you write the rules in your .war project, not in an apache with mod_rewrite.

Go here for the library's project on googlecode.

in the urlrewrite.xml write :

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.1//EN" "http://www.tuckey.org/res/dtds/urlrewrite3.1.dtd">
<urlrewrite>
    <rule match-type="regex">  
      <note>Remove trailing slash</note>
      <from>^(.*)/$</from>
      <to type="redirect">$1</to>
    </rule>  
</urlrewrite>

In the web.xml of your application, add :

<filter>
    <filter-name>UrlRewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
       <init-param>
            <param-name>confPath</param-name>
            <param-value>/WEB-INF/urlrewrite.xml</param-value>
        </init-param>
</filter>
<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

Beware, the declaration order of the filters in the web.xml is important, so try to declare this one before anything from spring.

Of course, this is but a fraction of what UrlRewriteFilter can do.

Regards.

Solution 3

Not sure if spring 3.0 had this, but spring 3.1 RequestMappingHandlerMapping allows you to set a "useTrailingSlashMatch" property. By default it is true.

I think switching it to false would solve your issue, however it would affect ALL mappings handled by RequestMappingHandlerMapping across your application... so you may have a fair amount of regression to do.

Solution 4

This usually works for me with URLRewriteFilter in Spring.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN" 
 "http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd">
<urlrewrite>
    <rule>
         <note>Remove trailing slash for SEO purposes</note>
         <from>/**/</from>
         <to type="permanent-redirect">%{context-path}/$1</to>
    </rule>
</urlrewrite>
Share:
24,704
Randomize
Author by

Randomize

Just a random developer that does NOT believe in software development and people

Updated on July 09, 2022

Comments

  • Randomize
    Randomize almost 2 years

    Spring MVC (3.0) considers URLs with and without trailing slashes as the same URL.

    For example:

    http://www.example.org/data/something = http://www.example.org/data/something/

    I need to redirect the URL with trailing slashes

    http://www.example.org/data/something/

    to the URL without it:

    http://www.example.org/data/something

    I need to do this internally the application (so not rewrite rules via Apache, etc).

    A way to do it is:

    @ResponseStatus(value=HttpStatus.MOVED_PERMANENTLY)
    @RequestMapping(value = "/data/something/")
    public String dataSomethingRedirect(...) {
        return "redirect:/data/something";
    }
    

    but this has generally 2 problems:

    1. too many controllers
    2. problem with parameters: like wrong encoding

    Question

    Is there a way to intercept all the URLs and in case they have a trailing slash, redirect them to the relative one without slash?