如何将带有斜杠的 URL 重定向到没有斜杠的相应 URL?
Posted
技术标签:
【中文标题】如何将带有斜杠的 URL 重定向到没有斜杠的相应 URL?【英文标题】:How to redirect URLs with trailing slash to the corresponding ones without it? 【发布时间】:2012-02-01 10:35:07 【问题描述】:Spring MVC (3.0) 将带有和不带有斜杠的 URL 视为相同的 URL。
例如:
http://www.example.org/data/something = http://www.example.org/data/something/
我需要用尾部斜杠重定向 URL
http://www.example.org/data/something/
到没有它的 URL:
http://www.example.org/data/something
我需要在应用程序内部执行此操作(因此不要通过 Apache 等重写规则)。
一种方法是:
@ResponseStatus(value=HttpStatus.MOVED_PERMANENTLY)
@RequestMapping(value = "/data/something/")
public String dataSomethingRedirect(...)
return "redirect:/data/something";
但这通常有两个问题:
-
控制器过多
参数问题:比如错误编码
问题
有没有办法拦截所有的 URL,如果它们有斜杠,将它们重定向到不带斜杠的相对 URL?
【问题讨论】:
如果一个总是重定向到另一个,它们不是同样等价的吗?实现这一目标所涉及的努力可能很高。如果您的担心完全是表面上的,那根本不值得。 在相对 url 链接方面它们并不等价 【参考方案1】:你可以在你的 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 和请求+响应;所以你可以:
response.sendRedirect("http://example.org/whitout-trailing-slash");
你不想看的答案
在考虑 HTTP 时,这种行为(带有斜杠的 URL = 没有它的 URL)是完全“有效的”。至少这是 Spring 的默认行为,您可以使用 useTrailingSlashMatch
(see javadoc) 禁用它。
因此在前端服务器上使用重写/重定向规则可能是一个解决方案;但同样,我不知道您的限制(也许您可以详细说明一下,我们可以找出其他解决方案?)。
【讨论】:
感谢您的回答。我正在考虑将 HandlerInterceptor 与我的“preHandle”版本一起使用(实际上我做到了)。问题是由于“搜索引擎优化”的原因,因为谷歌对带有和不带“/”的相同页面的排名不被认为是好的。 所以您正在考虑出于 SEO 原因放弃这种方法?这是个好主意 - 我认为 SEO 只是众多原因之一...... 好吧,我不知道这是一个很好的理由。但是您的访问者可能只会写您的家庭网址。其余请求通常来自您自己的链接。 仅供参考,有一个 JIRA 请求为这种情况添加一个 HandlerInterceptor (jira.springsource.org/browse/SPR-8473)。 "这种行为(带有斜杠的 URL = 没有它的 URL)在考虑 HTTP 时是完全“有效的”。”。不,就 HTTP 而言,http://example.org/blabla
和 http://example.org/blabla/
(甚至http://example.org/blabla//
)是不同的 URL。许多服务器会将它们视为相同,但这是调度机制的实现选择。 Apache Httpd 默认启用 (DirectorySlash On
),但这是一个选项。【参考方案2】:
我认为您最好的选择是在进入 Spring web 的 servlet 之前使用 UrlRewriteFilter 执行此操作。这将确保您的重定向规则不会影响您的控制器。
请注意,您在 .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 中过滤器的声明顺序很重要,因此请尝试在 spring 之前声明此顺序。
当然,这只是 UrlRewriteFilter 可以做的一小部分。
问候。
【讨论】:
好提示!实际上,您可能希望将 from 指定为这通常对我在 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>
【讨论】:
【参考方案4】:不确定 spring 3.0 是否有此功能,但 spring 3.1 RequestMappingHandlerMapping 允许您设置“useTrailingSlashMatch”属性。默认为真。
我认为将其切换为 false 可以解决您的问题,但它会影响 RequestMappingHandlerMapping 在您的应用程序中处理的所有映射...因此您可能需要进行大量回归。
【讨论】:
【参考方案5】:我同意@Brian Clozel 的观点:我不认为做你想做的事是个好主意。那么,为什么需要它?
无论如何,我认为最简单的解决方案是编写自定义javax.servlet.Filter
。所以,没有Spring依赖。如果请求 URL 以斜杠结尾,您只需重定向到没有它的相同 url。但要小心:
必须将所有参数(GET 和 POST)添加为 GET 参数。您确定您的应用程序方法不可知?
您可能会遇到一些编码问题。在过滤器中,您可以将 POST 参数编码为所需的编码。但是您的应用程序中未配置 GET 参数的默认编码。在 server.xml 中配置(如果是 Tomcat),默认值为 ISO-8859-1。
祝你好运!
【讨论】:
【参考方案6】:基于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>
【讨论】:
【参考方案7】:我发现这也可以通过在 @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 时做出应有的响应。
【讨论】:
以上是关于如何将带有斜杠的 URL 重定向到没有斜杠的相应 URL?的主要内容,如果未能解决你的问题,请参考以下文章
如何禁用 301 重定向,在 Apache 中将斜杠添加到目录名称
Web.config:使用尾部斜杠将URL输入重定向到URL而不使用尾部斜杠