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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3125296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:40:04  来源:igfitidea点击:

Can I exclude some concrete urls from <url-pattern> inside <filter-mapping>?

javaservletsservlet-filters

提问by Roman

I want some concrete filter to be applied for all urls except for one concrete (i.e. for /*except for /specialpath).

我想要一些具体的过滤器应用于所有网址,除了一个具体的(即/*除了/specialpath)。

Is there a possibility to do that?

有没有可能做到这一点?



sample code:

示例代码:

<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>

采纳答案by BalusC

The standard Servlet API doesn't support this facility. You may want either to use a rewrite-URL filter for this like Tuckey's one(which is much similar Apache HTTPD's mod_rewrite), or to add a check in the doFilter()method of the Filter listening on /*.

标准 Servlet API 不支持此功能。您可能希望为此使用重写 URL 过滤器,例如Tuckey 的过滤器(与 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.
}

You can if necessary specify the paths-to-be-ignored as an init-paramof the filter so that you can control it in the web.xmlanyway. You can get it in the filter as follows:

如有必要,您可以将要忽略的路径指定为init-param过滤器的一个,以便您可以在web.xml任何情况下控制它。您可以按如下方式在过滤器中获取它:

private String pathToBeIgnored;

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

If the filter is part of 3rd party API and thus you can't modify it, then map it on a more specific url-pattern, e.g. /otherfilterpath/*and create a new filter on /*which forwards to the path matching the 3rd party filter.

如果过滤器是第 3 方 API 的一部分,因此您无法修改它,则将其映射到更具体的url-pattern,例如/otherfilterpath/*并创建一个新过滤器,在/*该过滤器上转发到与第 3 方过滤器匹配的路径。

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

To avoid that this filter will call itself in an infinite loop you need to let it listen (dispatch) on REQUESTonly and the 3rd party filter on FORWARDonly.

为避免此过滤器在无限循环中调用自身,您需要让它仅侦听(调度)REQUEST并且仅启用第 3 方过滤器FORWARD

See also:

也可以看看:

回答by rsp

I don't think you can, the only other configuration alternative is to enumerate the paths that you want to be filtered, so instead of /*you could add some for /this/*and /that/*etc, but that won't lead to a sufficient solution when you have alot of those paths.

我不认为你可以,唯一的其他配置的选择是枚举要被过滤的路径,所以不是/*你可以添加一些对/this/*/that/*等,但是当你有很多的,不会引起足够的解决方案那些路径。

What you can do is add a parameter to the filter providing an expression (like a regular expression) which is used to skip the filter functionality for the paths matched. The servlet container will still call your filter for those url's but you will have better control over the configuration.

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

Edit

编辑

Now that you mention you have no control over the filter, what you could do is either inherit from that filter calling supermethods in its methods except when the url path you want to skip is present and follow the filter chain like @BalusC proposed, or build a filter which instantiates your filter and delegates under the same circumstances. In both cases the filter parameters would include both the expression parameter you add and those of the filter you inherit from or delegate to.

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

The advantage of building a delegating filter (a wrapper) is that you can add the filter class of the wrapped filter as parameter and reuse it in other situations like this one.

构建委托过滤器(包装器)的优点是您可以将包装过滤器的过滤器类添加为参数,并在其他情况下重复使用,例如这种情况。

回答by mrzasa

I used an approach described by Eric Daugherty: I created a special servlet that always answers with 403 code and put its mapping before the general one.

我使用了Eric Daugherty 描述的一种方法:我创建了一个特殊的 servlet,它总是用 403 代码回答并将其映射放在一般的之前。

Mapping fragment:

映射片段:

  <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>

And the servlet class:

和 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);
    }
}

回答by kvitso

This approach works when you want to prevent a certain filter and all the following ones. It should work well if you eg. want to serve some content as static resources within your servlet container instead of letting your application logic (through a filter like GuiceFilter):

当您想要阻止某个过滤器和所有以下过滤器时,此方法有效。如果你,它应该工作得很好。想要在您的 servlet 容器中提供一些内容作为静态资源,而不是让您的应用程序逻辑(通过像 GuiceFilter 这样的过滤器):

Map the folder with your static resource files to the default servlet. Create a servlet filter and put it beforethe GuiceFilter in your web.xml. In your created filter, you can separate between forwarding some requests to the GuiceFilter and others directly to the dispatcher. Example follows...

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

web.xml

网页.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

静态资源过滤器.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");
    }
}

Unfortunately if you just want to skip a single step in the filter chain while keeping those that follows, this will not work.

不幸的是,如果您只想跳过过滤器链中的一个步骤,同时保留后面的步骤,这将不起作用。

回答by Sindhu

I also Had to filter based on the URL pattern(/{servicename}/api/stats/)in java code .

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

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

But its bizarre, that servlet doesn't support url pattern other than (/*), This should be a very common case for servlet API's !

但奇怪的是,servlet 不支持 (/*) 以外的 url 模式,这应该是 servlet API 的一个非常常见的情况!

回答by nelson

I have encounterd the same issue, but I find a anwser showing below.

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

web.xml

网页.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

过滤器.java

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

this way you don't have to harass the concrete Filter class.

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

回答by robermann

If for any reason you cannot change the original filter mapping ("/*" in my case) and you are dispatching to an unchangeable third-party filter, you can find useful the following:

如果由于任何原因您无法更改原始过滤器映射(在我的情况下为“/*”)并且您要分派到不可更改的第三方过滤器,您会发现以下有用:

  • Intercept the path to be bypassed
  • Skip to and execute the last ring of the filter chain (the servlet itself)
  • The skipping is done via reflection, inspecting the container instances in debug mode
  • 拦截要绕过的路径
  • 跳到并执行过滤器链的最后一个环(servlet 本身)
  • 跳过是通过反射完成的,在调试模式下检查容器实例

The following works in Weblogic 12.1.3:

以下工作在 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();
              }           
          }   
      }
      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();
              }           
          }   
      }