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

前端 未结 7 1568
遥遥无期
遥遥无期 2020-12-05 10:12

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

For example:

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

相关标签:
7条回答
  • 2020-12-05 10:48

    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?).

    0 讨论(0)
  • 2020-12-05 10:48

    Based on SEO, I think it is important to make a distinction.

    If the URL that finished in the trailing slash exist, is indexed in the search engines and there are links on Internet, a permanent redirection (301) is required as Uddhav Kambli says. The standard redirection (302) will be better than having a duplicated URL, but is not good enough.

    However, if the URL never existed, it is not indexed on Internet and there are no external links, the URL does not exist. Therefore a 404, page not found, is a better fit.

    WEB-INF/urlrewrite.xml

    <?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>
            <set type="status">404</set>
            <to>null</to>
        </rule>
    </urlrewrite>
    

    And in order to complete the configuration ...

    add to WEB-INF/web.xml

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

    Maven

    <dependency>
        <groupId>org.tuckey</groupId>
        <artifactId>urlrewritefilter</artifactId>
        <version>4.0.3</version>
    </dependency>
    
    0 讨论(0)
  • 2020-12-05 10:55

    I agree with @Brian Clozel: I don't think is a good idea to do what you want. So, why you need it?

    Anyway, I think the simplest solution is to write a custom javax.servlet.Filter. So, no Spring dependency. If the request URL ends with slash you just have to redirect to the same url without it. But caution:

    • All parameters (GET and POST) must be added as GET parameters. Are you sure that your application is method agnostic?

    • You can have some problems with encoding. In the filter you can encode POST parameters to the required encoding. But the default encoding for GET parameters is not configured in your application. Is configured in server.xml (if Tomcat) and default value is ISO-8859-1.

    Good luck!

    0 讨论(0)
  • 2020-12-05 10:57

    I have found that this can also be handled much more simply by using an ErrorViewResolver bean somewhere in your @Configuration:

    @Autowired
    private DefaultErrorViewResolver defaultErrorViewResolver;
    
    @Bean
    ErrorViewResolver errorViewResolver() {
        return new ErrorViewResolver() {
            @Override
            public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
                if(model.containsKey("path") && !model.get("path").toString().endsWith("/")) {
                    return new ModelAndView("redirect:"+model.get("path") + "/");
                }
                return defaultErrorViewResolver.resolveErrorView(request, status, model);
            }
        };
    }
    

    I'm not sure if this is good or bad practice, but it is effective in my circumstance, and does exactly what I need it to do for an arbitrary path 'foo': respond with a 302 redirect to /foo/ when you request /foo and respond as it should when you request /foo.

    0 讨论(0)
  • 2020-12-05 11:01

    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.

    0 讨论(0)
  • 2020-12-05 11:10

    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>
    
    0 讨论(0)
提交回复
热议问题