没有它,如何将带有斜杠的URL重定向到相应的URL?

时间:2012-01-03 11:10:48

标签: java spring spring-mvc redirect model-view-controller

Spring MVC(3.0)将带有和不带尾部斜杠的URL视为相同的URL。

例如:

  

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

我需要使用尾部斜杠重定向网址

  

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

到没有它的网址:

  

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

我需要在应用程序内部执行此操作(因此不要通过Apache重写规则等)。

一种方法是:

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

但这通常有两个问题:

  1. 太多控制器
  2. 参数问题:如错误编码
  3. 问题

    有没有办法拦截所有网址,如果它们有一个尾部斜杠,请将它们重定向到没有斜线的相对网址?

7 个答案:

答案 0 :(得分:14)

您可以在Web配置中列出所需的所有重写规则

如果没有多少,您可以配置像这样的重定向视图

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

或者您可以创建自定义HandlerInterceptor

但拦截器在请求映射到特定Controller.action之前发生,并且您无法知道该上下文中的控制器和操作。

你所拥有的只是HTTPServlet API和request + response;所以你可以:

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

您不想阅读的答案

当考虑HTTP时,此行为(具有尾部斜杠的URL =没有它的URL)完全“有效”。至少这是Spring的默认行为,您可以使用useTrailingSlashMatchsee javadoc)停用。

因此,在前端服务器上使用重写/重定向规则可以提供解决方案;但同样,我不知道你的约束(也许你可以详细说明这个,我们可以找出其他解决方案吗?)。

答案 1 :(得分:11)

我认为您最好选择在使用UrlRewriteFilter进入Spring Web的servlet之前执行此操作。这将确保您的重定向规则不会影响您的控制器。

请注意,您在.war项目中编写规则,而不是在mod_rewrite的apache中编写规则。

Go here用于googlecode上的图书馆项目。

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>
      <to type="redirect">$1</to>
    </rule>  
</urlrewrite>

在应用程序的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>

请注意,web.xml中过滤器的声明顺序很重要,因此请尝试在春天之前声明这个过滤器。

当然,这只是UrlRewriteFilter可以做的一小部分。

问候。

答案 2 :(得分:3)

这通常适用于Spring中的URLRewriteFilter。

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

答案 3 :(得分:3)

不确定spring 3.0是否有此功能,但是春季3.1 RequestMappingHandlerMapping允许您设置“useTrailingSlashMatch”属性。默认情况下是真的。

我认为将其切换为false会解决您的问题,但是它会影响您的应用程序中的RequestMappingHandlerMapping处理的所有映射...所以您可能需要进行大量的回归。

答案 4 :(得分:0)

我同意@Brian Clozel:我认为做你想做的事并不是一个好主意。那么,为什么需要呢?

无论如何,我认为最简单的解决方案是编写自定义javax.servlet.Filter。所以,没有Spring依赖。如果请求URL以斜杠结尾,则只需将其重定向到相同的URL即可。但请注意:

  • 必须将所有参数(GET和POST)添加为GET参数。您确定您的应用程序方法无关吗?

  • 您可能遇到编码问题。在过滤器中,您可以将POST参数编码为所需的编码。但是,您的应用程序中未配置GET参数的默认编码。在server.xml中配置(如果是Tomcat),默认值为ISO-8859-1。

祝你好运!

答案 5 :(得分:0)

基于SEO,我认为区分是很重要的。

如果在尾部斜杠中结束的URL存在,在搜索引擎中被索引并且Internet上有链接,则需要永久重定向(301),如Uddhav Kambli所说。标准重定向(302)将比拥有重复的URL更好,但还不够好。

但是,如果URL从不存在,则不在Internet上编制索引,并且没有外部链接,URL不存在。因此,找不到404页面是更合适的。

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>

并且为了完成配置......

添加到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>

答案 6 :(得分:0)

我发现通过在@Configuration中的某处使用ErrorViewResolver bean,可以更简单地处理这个问题:

@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);
        }
    };
}

我不确定这是好事还是坏事,但它在我的情况下是有效的,而且正是我需要它为任意路径'foo'做的事情:用302重定向回复/ foo /当你请求/ foo并在你请求/ foo时应该响应。