【问题标题】:Implement a URL Filter实现 URL 过滤器
【发布时间】:2014-05-06 14:53:43
【问题描述】:

带有 ServletFilter 的嵌入式 Tomcat 的简单实例:

            Tomcat tomcat = new Tomcat();
            Context rootCtx = tomcat.addContext("", base.getAbsolutePath());
            FilterDef filterDefinition = new FilterDef();
            filterDefinition.setFilterName(URLFilter.class.getSimpleName());
            filterDefinition.setFilterClass(URLFilter.class.getName());
            rootCtx.addFilterDef(filterDefinition);

            FilterMap filter1mapping = new FilterMap();
            filter1mapping.setFilterName(URLFilter.class.getSimpleName());
            filter1mapping.addURLPattern("/*");
            rootCtx.addFilterMap(filter1mapping);

            Tomcat.addServlet(rootCtx, "Servlet1", new Servlet1());
            rootCtx.addServletMapping("/Servlet1", "Servlet1");

URL 过滤器实现:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    Boolean filtered = false;
    System.out.println("request intercepted");
    if (request.getAttribute("filtered") != null) {
        filtered = true;
        request.setAttribute("filtered", filtered);
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.sendRedirect("/Servlet1");
        return;
    } else {
        filterChain.doFilter(request, response);
    }
}

由于某种原因,这最终会陷入无限循环,并且永远不会到达 Servlet1。实现 URL 过滤器的正确方法是什么,以便我可以在传递响应之前仔细检查请求周围的参数?

【问题讨论】:

  • 您似乎错过了对 chain.doFilter(request, response) 的呼叫。如果将其包含在 doFilter 方法的末尾,行为会改变吗?
  • 道歉 - 我最初的评论很仓促,而且不够具体。仅当您不发送重定向时才需要调用doFilter。当你重定向你应该只是return;之后,doFilter是你不重定向的时候。
  • 如果您要进行大量重定向,请查看UrlRewriteFilter。它就是为此目的而制作的。

标签: java tomcat servlets embedded-tomcat-7 tomcat8


【解决方案1】:

查看sendRedirect() 的JavaDocs。您在 每个请求 上告诉客户端返回到 /Servlet1,但随后您将无限期地过滤它。在某些时候,您需要停止在过滤器中发送重定向!

澄清更多。如果您不打算主动过滤请求,您唯一需要做的就是调用

filterChain.dofilter(request, response);

除非您真的要发送 HTTP 302(临时重定向),否则不要发回重定向。 Servlet 过滤器链是 servlet 进程的重要组成部分,尽管它可能看起来违反直觉,但您可以通过调用 filterChain.doFilter 命令使您的过滤器看起来什么都不做,该命令允许请求继续到您配置的其他过滤器应用服务器。

我不清楚过滤器试图做什么。如果您打算按 URL 过滤,则应查找匹配的 URL,然后仅在匹配时才重定向。

【讨论】:

  • 或许可以尝试从这个角度来看待它:您的过滤器如何知道它之前是否已经重定向了请求? 目前它不知道 - 它假定任何东西它接收到的还没有被重定向并重定向它。
  • 您可以在请求中添加一个属性,例如request.setAttribute("redirected", "true");,然后让过滤器检查该属性以查看它是否已被重定向。如果没有,修改属性然后重定向它,否则不要重定向它并沿着应用过滤器链传递请求。
  • 这个,但我认为你需要这样做else if (request.getRequestURI.equals("/Servlet1")) { filterChain.dofilter(request, response); }
【解决方案2】:

由于这解决了您的问题,因此将其发布为答案。

首先,您需要确保您是沿着应用程序过滤器链传递请求,或者您正在重定向它:

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

    Boolean filtered = false;
    System.out.println("request intercepted");
    if (!filtered) {
        filtered = true;
        ((HttpServletResponse) response).sendRedirect("/Servlet1");
        return;
    }

    filterChain.doFilter(request, response);
}

然后你需要确保过滤器知道传入的请求何时已经被重定向,这样它就不会再次重定向它:

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

    Boolean filtered = false;
    System.out.println("request intercepted");
    if (request.getAttribute("filtered") != null) {
        filtered = (Boolean) request.getAttribute("filtered");
    }

    if (!filtered) {
        request.setAttribute("filtered", Boolean.TRUE);
        ((HttpServletResponse) response).sendRedirect("/Servlet1");
        return;
    }

    filterChain.doFilter(request, response);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 2019-08-30
    • 2016-02-06
    • 2011-07-09
    相关资源
    最近更新 更多