Spring MVC(3.0)将带有和不带尾部斜杠的URL视为相同的URL。
例如:
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";
}
但这通常有两个问题:
有没有办法拦截所有网址,如果它们有一个尾部斜杠,请将它们重定向到没有斜线的相对网址?
答案 0 :(得分:14)
如果没有多少,您可以配置像这样的重定向视图
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/my/path/", "/my/path")
.setKeepQueryParams(true)
.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
}
但拦截器在请求映射到特定Controller.action
之前发生,并且您无法知道该上下文中的控制器和操作。
你所拥有的只是HTTPServlet API和request + response;所以你可以:
response.sendRedirect("http://example.org/whitout-trailing-slash");
当考虑HTTP时,此行为(具有尾部斜杠的URL =没有它的URL)完全“有效”。至少这是Spring的默认行为,您可以使用useTrailingSlashMatch
(see 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时应该响应。