Как перенаправить URL с косой чертой на соответствующие без него? - PullRequest
19 голосов
/ 03 января 2012

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";
}

но обычно это 2 проблемы:

  1. слишком много контроллеров
  2. проблема с параметрами: как неправильная кодировка

Вопрос

Есть ли способ перехватить все URL-адреса и, если они имеют косую черту, перенаправить их на относительную без косой черты?

Ответы [ 7 ]

14 голосов
/ 03 января 2012

Вы можете перечислить все необходимые правила переписывания в вашей веб-конфигурации

Если их не так много, вы можете настроить перенаправления следующим образом

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

Ответ, который вы не хотите читать

Такое поведение (URL с завершающей косой чертой = URL без него) совершенно "допустимо" при рассмотрении HTTP. По крайней мере, это поведение по умолчанию в Spring, которое можно отключить с помощью useTrailingSlashMatch ( см. Javadoc ).

Таким образом, использование правил перезаписи / перенаправления на сервере переднего плана может стать решением; но опять же, я не знаю ваших ограничений (может быть, вы могли бы уточнить это, и мы могли бы найти другие решения?).

11 голосов
/ 03 января 2012

Я думаю, что вам лучше всего сделать это перед входом в сервлет Spring, используя UrlRewriteFilter. Это гарантирует, что ваши правила перенаправления не повлияют на ваши контроллеры.

Обратите внимание, что вы пишете правила в своем .war-проекте, а не в Apache с mod_rewrite.

Перейдите сюда для проекта библиотеки на 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.

Привет.

3 голосов
/ 14 июня 2012

Не уверен, что это имеет весна 3.0, но весна 3.1 RequestMappingHandlerMapping позволяет установить свойство «useTrailingSlashMatch». По умолчанию это правда.

Я думаю, что переключение на false решит вашу проблему, однако это повлияет на ВСЕ сопоставления, обрабатываемые RequestMappingHandlerMapping в вашем приложении ... так что у вас может быть достаточно регрессии.

3 голосов
/ 05 марта 2012

Это обычно работает для меня с URLRewriteFilter в 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 голосов
/ 27 апреля 2018

Я обнаружил, что это также может быть обработано намного проще с помощью bean-компонента ErrorViewResolver где-то в вашей @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);
        }
    };
}

Я не уверен, является ли это хорошей или плохой практикой, но этоэффективен в моих обстоятельствах и делает именно то, что мне нужно для произвольного пути 'foo': ответьте перенаправлением 302 на / foo /, когда вы запрашиваете / foo, и отвечайте, как следует, когда вы запрашиваете /foo.*1004.*

0 голосов
/ 13 июня 2014

Основываясь на SEO, я думаю, что важно провести различие.

Если URL, который закончился в конце косой черты, существует, индексируется в поисковых системах и есть ссылки в Интернете, постоянное перенаправление(301) требуется, как говорит Уддхав Камбли.Стандартное перенаправление (302) будет лучше, чем наличие дублированного URL-адреса, но этого недостаточно.

Однако, если URL-адрес никогда не существовал, он не индексируется в Интернете и нет внешних ссылок, 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>
0 голосов
/ 03 января 2012

Я согласен с @Brian Clozel: я не думаю, что это хорошая идея делать то, что вы хотите.Итак, зачем вам это нужно?

В любом случае, я думаю, что самое простое решение - написать кастом javax.servlet.Filter.Таким образом, нет зависимости от Spring.Если URL запроса заканчивается косой чертой, вам просто нужно перенаправить на тот же URL без него.Но будьте осторожны:

  • Все параметры (GET и POST) должны быть добавлены как параметры GET.Вы уверены, что ваше приложение является независимым от метода ?

  • У вас могут быть проблемы с кодировкой.В фильтре вы можете закодировать параметры POST в требуемую кодировку.Но кодировка по умолчанию для параметров GET не настроена в вашем приложении.Настраивается в файле server.xml (если Tomcat) и по умолчанию используется значение ISO-8859-1.

Удачи!

...