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

时间:2010-06-26 19:47:40

标签: java servlets servlet-filters

我想要一些具体的过滤器应用于除了一个具体的所有网址之外(例如/*除了/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>

8 个答案:

答案 0 :(得分:144)

标准Servlet API不支持此功能。您可能希望对此使用重写URL过滤器,如Tuckey's one(与Apache HTTPD的mod_rewrite非常相似),或者在过滤器侦听的doFilter()方法中添加检查在/*

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上进行第三方过滤。

另见:

答案 1 :(得分:13)

我使用了一种方法described by Eric Daugherty:我创建了一个特殊的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);
    }
}

答案 2 :(得分:7)

当您想要阻止某个过滤器和所有以下过滤器时,此方法有效。如果你这样做应该会很好。想要将一些内容作为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");
    }
}

不幸的是,如果你只想跳过过滤器链中的一个步骤,同时保留随后的步骤,这将无效。

答案 3 :(得分:3)

我认为你不能,唯一的其他配置选择是枚举你想要过滤的路径,所以你可以为/*而不是/this/*添加一些/that/*和{{1}等等,但当你有很多这样的路径时,这不会导致足够的解决方案。

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

修改

现在您提到您无法控制过滤器,您可以做的是从其方法中继承调用super方法的过滤器,除非您要跳过的url路径存在并遵循过滤器像@BalusC建议的链,或构建一个过滤器,在相同的情况下实例化你的过滤器和委托。在这两种情况下,过滤器参数都包括您添加的表达式参数以及您从中继承或委托的过滤器的参数。

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

答案 4 :(得分: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的一个非常常见的情况!

答案 5 :(得分:0)

我遇到了同样的问题,但我发现下面有一个anwser。

的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类。

答案 6 :(得分:0)

如果由于任何原因您无法更改原始过滤器映射(&#34; / *&#34;在我的情况下)并且您要发送到不可更改的第三方过滤器,您可以找到以下内容:

  • 拦截要绕过的路径
  • 跳过并执行过滤器链的最后一个环(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();
              }           
          }   
      }

答案 7 :(得分:0)

我能够在Spring 2中按以下方式处理

 private boolean isInPath(ServletRequest request) {
   String PATH_TO_VALIDATE = "/path/";
   String path = ((HttpServletRequest) request).getRequestURI();
   return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}