Spring 在应用过滤器时区分带和不带尾部斜线的路径
Spring differentiates path with and without trailing slash when applying filters
我正在开发一个 Spring 引导应用程序,我想在某些特定的 URL 中应用一些过滤器,为此我正在实现 Filter
接口(下面的代码)并使用 FilterRegistrationBean
其中我有方法 setUrlPatterns
来定义使用过滤器的端点。我从头开始创建了一个示例应用程序,并为 /hello
设置了过滤器,但过滤器不适用于 /hello/
.
这使得有必要将行从
filterRegistrationBean.setUrlPatterns(List.of("/hello"));
到
filterRegistrationBean.setUrlPatterns(List.of("/hello", "/hello/"));
。它解决了我的问题,但我不想复制仅包含尾部斜杠的路径。
有没有更好的方法来代替 List.of("/hello", "/hello/")
?
代码:
import javax.servlet.*;
import java.io.IOException;
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("-----------------FILTER-----------------");
chain.doFilter(request, response);
}
// ... other methods
}
import com.example.demo.config.filters.LogFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
var filterRegistrationBean = new FilterRegistrationBean<>(new LogFilter());
filterRegistrationBean.setUrlPatterns(List.of("/hello"));
return filterRegistrationBean;
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController()
@RequestMapping("/hello")
public class HelloController {
@GetMapping
public String hello() {
return "Hello";
}
}
研究:
- 还有一种定义过滤器的方法,启用
@ServletComponentScan
,创建一个实现Filter
的class并用@WebFilter(urlPatterns = {"/hello"})
注释,但结果是一样的.
- 我可以使用
/hello/*
,它会考虑带和不带尾部斜杠的路径,但我不想对 /hello/abc/
等其他所有内容应用过滤器,我想应用仅针对 /hello
(和 /hello/
)进行过滤。
我在嵌入式 Tomcat 上进行了调试,我发现 ApplicationFilterFactory 它使用一些逻辑来决定何时在路径中应用过滤器,它看起来重复路径是唯一的解决方案,但在这个例子中我只使用一个路径,假设你有 20..30 个路径用于这个过滤器,一旦复制以包含尾部斜线它就变成 40..60,所以我试图为此找到另一个解决方案(由于嵌入式 tomcat).
上的 ApplicationFilterFactory
实现,我不确定是否有其他解决方案
See here :
setUrlPatterns
public void setUrlPatterns(Collection<String> urlPatterns)
Set the URL patterns that the filter will be registered against. This will replace any previously specified URL patterns.
...
此方法的变体(具有更精确的文档):
addUrlPatterns
public void addUrlPatterns(String... urlPatterns)
Add URL patterns, as defined in the Servlet specification, that the filter will be registered against.
...(搜索;):
- => Servlet Spec
- =>(最新)3.1.final:
12.2 Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define mappings:
- A string beginning with a
/
character and ending with a /*
suffix is used for path mapping.
- A string beginning with a
*.
prefix is used as an extension mapping.
- The empty string (
""
) is a special URL pattern that exactly maps to the
application's context root, i.e., requests of the form
http://host:port/<contextroot>/
. In this case the path info is /
and the servlet path and context path is empty string (""
).
- A string containing only the
/
character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.
- All other strings are used for exact matches only.
If the effective web.xml (after merging information from fragments and annotations) contains any url-patterns that are mapped to multiple servlets then the deployment must fail.
所以对于你的核心问题:
Is there a better way to do this instead write List.of("/hello", "/hello/")?
不(抱歉),Servlet <=3.1 不支持。根据此规范,"hello", "hello/"
将是 两个 完全匹配。
(并且 List.of(few, ..., items)
是“非常酷”/最新的/不可变的!;))
我正在开发一个 Spring 引导应用程序,我想在某些特定的 URL 中应用一些过滤器,为此我正在实现 Filter
接口(下面的代码)并使用 FilterRegistrationBean
其中我有方法 setUrlPatterns
来定义使用过滤器的端点。我从头开始创建了一个示例应用程序,并为 /hello
设置了过滤器,但过滤器不适用于 /hello/
.
这使得有必要将行从
filterRegistrationBean.setUrlPatterns(List.of("/hello"));
到
filterRegistrationBean.setUrlPatterns(List.of("/hello", "/hello/"));
。它解决了我的问题,但我不想复制仅包含尾部斜杠的路径。
有没有更好的方法来代替 List.of("/hello", "/hello/")
?
代码:
import javax.servlet.*;
import java.io.IOException;
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("-----------------FILTER-----------------");
chain.doFilter(request, response);
}
// ... other methods
}
import com.example.demo.config.filters.LogFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
var filterRegistrationBean = new FilterRegistrationBean<>(new LogFilter());
filterRegistrationBean.setUrlPatterns(List.of("/hello"));
return filterRegistrationBean;
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController()
@RequestMapping("/hello")
public class HelloController {
@GetMapping
public String hello() {
return "Hello";
}
}
研究:
- 还有一种定义过滤器的方法,启用
@ServletComponentScan
,创建一个实现Filter
的class并用@WebFilter(urlPatterns = {"/hello"})
注释,但结果是一样的. - 我可以使用
/hello/*
,它会考虑带和不带尾部斜杠的路径,但我不想对/hello/abc/
等其他所有内容应用过滤器,我想应用仅针对/hello
(和/hello/
)进行过滤。
我在嵌入式 Tomcat 上进行了调试,我发现 ApplicationFilterFactory 它使用一些逻辑来决定何时在路径中应用过滤器,它看起来重复路径是唯一的解决方案,但在这个例子中我只使用一个路径,假设你有 20..30 个路径用于这个过滤器,一旦复制以包含尾部斜线它就变成 40..60,所以我试图为此找到另一个解决方案(由于嵌入式 tomcat).
上的ApplicationFilterFactory
实现,我不确定是否有其他解决方案
See here :
setUrlPatterns
public void setUrlPatterns(Collection<String> urlPatterns)
Set the URL patterns that the filter will be registered against. This will replace any previously specified URL patterns. ...
此方法的变体(具有更精确的文档):
addUrlPatterns
public void addUrlPatterns(String... urlPatterns)
Add URL patterns, as defined in the Servlet specification, that the filter will be registered against.
...(搜索;):
- => Servlet Spec
- =>(最新)3.1.final:
12.2 Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define mappings:
- A string beginning with a
/
character and ending with a/*
suffix is used for path mapping.- A string beginning with a
*.
prefix is used as an extension mapping.- The empty string (
""
) is a special URL pattern that exactly maps to the application's context root, i.e., requests of the formhttp://host:port/<contextroot>/
. In this case the path info is/
and the servlet path and context path is empty string (""
).- A string containing only the
/
character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.- All other strings are used for exact matches only.
If the effective web.xml (after merging information from fragments and annotations) contains any url-patterns that are mapped to multiple servlets then the deployment must fail.
所以对于你的核心问题:
Is there a better way to do this instead write List.of("/hello", "/hello/")?
不(抱歉),Servlet <=3.1 不支持。根据此规范,"hello", "hello/"
将是 两个 完全匹配。
(并且 List.of(few, ..., items)
是“非常酷”/最新的/不可变的!;))