我可以从<filter-mapping>内部的<url-pattern>中排除一些具体的url吗?


127

我希望对所有网址应用一种具体的过滤器,除了一种具体的(即/*除外/specialpath)。

有可能这样做吗?


样例代码:

<filter>
    <filter-name>SomeFilter</filter-name>
    <filter-class>org.somproject.AFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SomeFilter</filter-name>
    <url-pattern>/*</url-pattern>   <!-- the question is: how to modify this line?  -->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Answers:


156

标准Servlet API不支持此功能。您可能想要为此使用重写URL过滤器,例如Tuckey的过滤器(与Apache HTTPD的过滤器非常相似mod_rewrite),或者doFilter()在Filter侦听的方法中添加一个检查/*

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    // Do your business stuff here for all paths other than /specialpath.
}

如有必要,可以将要忽略的路径指定为init-param过滤器的,以便web.xml无论如何都可以对其进行控制。您可以按以下方式在过滤器中获取它:

private String pathToBeIgnored;

public void init(FilterConfig config) {
    pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}

如果过滤器是第三方API的一部分,因此您不能对其进行修改,则将其映射到更具体的url-pattern,例如/otherfilterpath/*,创建一个新过滤器,/*并转发到与第三方过滤器匹配的路径。

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}

为避免此过滤器在无限循环中调用自己,您需要让其REQUEST仅在(第三方)过滤器上侦听(调度)FORWARD

也可以看看:


3
我的问题是过滤器不是我的,它来自组件库。
罗曼2010年

4
Ypu应该使用组件库过滤器并对其进行扩展,以添加要用于执行排除的代码。
gbtimmon 2012年

@BalusC如果“ / specialpath”仅提供js,css等静态资源,chain.doFilter()是否会使响应变慢?是否有一种无需链接过滤器即可直接提供资源的方法?
BenhurCD 2014年

@BenhurCD:我真的不知道您怎么能解决这个性能问题。
BalusC 2014年

13

我使用了Eric Daugherty所描述的方法:我创建了一个特殊的servlet,该servlet始终以403代码回答,并将其映射放在通用代码之前。

映射片段:

  <servlet>
    <servlet-name>generalServlet</servlet-name>
    <servlet-class>project.servlet.GeneralServlet</servlet-class>
  </servlet>
 <servlet>
    <servlet-name>specialServlet</servlet-name>
    <servlet-class>project.servlet.SpecialServlet</servlet-class>
 </servlet>
 <servlet-mapping>
    <servlet-name>specialServlet</servlet-name>
    <url-pattern>/resources/restricted/*</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
    <servlet-name>generalServlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
 </servlet-mapping>

和servlet类:

public class SpecialServlet extends HttpServlet {
    public SpecialServlet() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
}

9

当您要防止使用某个过滤器和以下所有过滤器时,此方法有效。如果您例如它应该运作良好。希望将某些内容作为servlet容器内的静态资源提供服务,而不是让您的应用程序逻辑(通过类似GuiceFilter的过滤器):

将包含静态资源文件的文件夹映射到默认servlet。创建一个servlet过滤器,并将其放在web.xml中的GuiceFilter 之前。在创建的过滤器中,您可以将转发给GuiceFilter的一些请求和转发给分派器的其他请求分开。示例如下...

web.xml

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>StaticResourceFilter</filter-name>
    <filter-class>com.project.filter.StaticResourceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>StaticResourceFilter</filter-name>
    <url-pattern>/static/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

StaticResourceFilter.class

public class StaticResourceFilter implements Filter {

    private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);

    private static final String RESOURCE_PATH = "/static/";
    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        LOGGER.info("StaticResourceFilter initialized");
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain chain) throws IOException, ServletException {

        String path = ((HttpServletRequest) request).getServletPath();
        if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
            request.getRequestDispatcher(path).forward(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        LOGGER.info("StaticResourceFilter destroyed");
    }
}

不幸的是,如果您只想跳过过滤器链中的单个步骤,而又保留后面的步骤,则此操作将无效。


我尝试使用您的解决方案,但是对于我应用了过滤器并中断链接的文件,出现了跟随错误;过滤器引发的未捕获的异常静态资源过滤器:java.io.FileNotFoundException。知道为什么吗?
shamaleyte

在多上下文设置中,使用.getRequestURI()会中断(最可能导致404),因为它是相对于上下文路径.getRequestDispatcher解析的。如果您的上下文路径为,那么在您的示例中,请求URI将为,并且使用会导致它针对的是解析。修复:使用代替。我将提交修改以解决此问题,但只想发表评论。仅供参考/a/a/staticgetRequestDispatcher("/a/static")/a/a/static.getServletPath().getRequestURI()
Reid,

3

我不认为可以,唯一的另一种配置替代方法是枚举要过滤的路径,因此,/*您可以添加for /this/*/that/*etc 的路径,但是当您拥有很多路径时,这将无法提供足够的解决方案这些路径。

您可以做的是在过滤器中添加一个参数,以提供一个表达式(如正则表达式),该表达式用于跳过匹配路径的过滤器功能。Servlet容器仍将为这些URL调用过滤器,但您将更好地控制配置。

编辑

既然您提到您对过滤器没有控制权,那么您可以做的是从其super方法中的那个过滤器调用方法继承,除非您要跳过的网址路径存在并且遵循@BalusC提议的过滤器链,或者构建一个在相同情况下实例化您的过滤器和委托的过滤器。在这两种情况下,过滤器参数都将包括您添加的expression参数和您从中继承或委托给它的过滤器参数。

构建委派过滤器(包装器)的优点是,您可以将包装的过滤器的过滤器类添加为参数,并在其他类似情况下重用它。


3

我还不得不根据Java代码中的URL模式(/ {servicename} / api / stats /)进行过滤。

if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);            
}

但是奇怪的是,servlet除了(/ *)之外不支持url模式,这对于servlet API来说应该是很常见的情况!


0

我也遇到过同样的问题,但是下面显示了一个答案。

web.xml

 <!-- set this param value for the filter-->
    <init-param>
            <param-name>freePages</param-name>
            <param-value>
            MainFrame.jsp;
            </param-value>
    </init-param>

filter.java

strFreePages = config.getInitParameter("freePages"); //get the exclue pattern from config file
isFreePage(strRequestPage)  //decide the exclude path

这样,您就不必骚扰具体的Filter类。


0

如果由于某种原因您无法更改原始过滤器映射(在我的情况下为“ / *”),并且正在分派到不可更改的第三方过滤器,则可以发现以下内容:

  • 拦截要绕过的路径
  • 跳到并执行过滤器链的最后一个环(servlet本身)
  • 跳过是通过反射完成的,在调试模式下检查容器实例

以下内容在Weblogic 12.1.3中有效:

      import org.apache.commons.lang3.reflect.FieldUtils;
      import javax.servlet.Filter;

      [...]

      @Override   
      public void doFilter(ServletRequest request, ServletRespons response, FilterChain chain) throws IOException, ServletException { 
          String path = ((HttpServletRequest) request).getRequestURI();

          if(!bypassSWA(path)){
              swpFilterHandler.doFilter(request, response, chain);

          } else {
              try {
                  ((Filter) (FieldUtils.readField(
                                (FieldUtils.readField(
                                        (FieldUtils.readField(chain, "filters", true)), "last", true)), "item", true)))
                  .doFilter(request, response, chain);
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }           
          }   
      }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.