首页 > 解决方案 > Spring拦截器拦截较晚

问题描述

Spring boot 2.1.7 运行测试服务器 - 需要使用 url 作为键检查我的缓存是否命中,然后根据缓存命中与否采取行动。

我从我的浏览器发送请求https://localhost:8443/test/param=value --- 我的过滤器选择它,并使用 SO 上另一个答案中的代码,过滤器构造了 url——过滤器代码看到网址是https://localhost:8443/test?param=value 太好了!然后我的拦截器被击中(感谢 Theo on SO),但它认为 url 是https://localhost:8443/favicon.ico——这是怎么回事?如果我没有拦截到原始 /test url,那么拦截器就不算什么了。

为了解决这个问题,在过滤器中,我将“真实”url 存储在 ServletContext 中,并且该变量在拦截器中被正确读取。看起来像一个可怕的黑客,我必须这样做很愚蠢。现在我已经硬编码了重定向到 url /test2 的决定,但回到 Chrome 中,我看到的是 test1 的输出,而不是 test2。

Chrome 中的网络选项卡似乎建议:来自 favicon 的 test1 输出和重定向

我被重定向到 test2,但只有在插入了对 favicon 的请求之后(无论出于何种神秘原因),但如图所示,输出显然是 test1,而不是 test2。

我不明白的是 devtools 还显示了来自 test2 的响应:

devtools 中的 test2 输出

@WebFilter( urlPatterns = "/test", description = "测试 servlet 过滤器", initParams = { @WebInitParam( name = "msg", value = "==> " ) }, filterName = "test filter" ) public类 TestFilter 实现过滤器 {

private FilterConfig filterConfig;


@Override
public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain )
        throws IOException, ServletException
{
    String url = getCurrentUrlFromRequest( servletRequest );
    // in the debugger, url is correctly shown as
    //  https://localhost:8443/test/param=value
    if ( null != url )
    {
        ServletContext s = servletRequest.getServletContext();
        s.setAttribute( "realUrl", url );
    }
    servletResponse.getOutputStream().print( filterConfig.getInitParameter( "msg" ) );
    filterChain.doFilter( servletRequest, servletResponse );

public String getCurrentUrlFromRequest( ServletRequest request )
{
    if ( !( request instanceof HttpServletRequest ) ) return null;

    return getCurrentUrlFromRequest( (HttpServletRequest) request );
}

public String getCurrentUrlFromRequest( HttpServletRequest request )
{
    StringBuffer requestURL = request.getRequestURL();
    String queryString = request.getQueryString();

    if ( queryString == null ) return requestURL.toString();

    return requestURL.append( '?' ).append( queryString ).toString();
}

@Override
public void destroy()
{
}

@Override
public void init( FilterConfig filterConfig ) throws ServletException
{
    this.filterConfig = filterConfig;
}

}

//然后是拦截器:

@Component 公共类 CheckForCacheInterceptor 实现 HandlerInterceptor {

@Bean
public MappedInterceptor myInterceptor()
{
    CheckForCacheInterceptor ci = new CheckForCacheInterceptor();
    ci.setRedirectMapping( "/test2" );
    return new MappedInterceptor( null, ci  );
}

private String redirectMapping;

@Override
public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler )
{
    String url = (String) request.getServletContext().getAttribute( "realUrl" );
    // "realUrl" has https://localhost:8443/test/param=value, but I'd like 
    // to get rid of hack.  Problem is that right here, running the same 
    // exact code (copy/paste of filter's
    // getCurrentUrlFromRequest( HttpServletRequest request ) method )
    //which gets the correct url in the filter yields 
    // https://localhost:8443/favicon.ico  -- where did that come from?

    // TODO check cache using requestUrl as key

    boolean foundInCache = false;
    if ( foundInCache ) 
    {
        // TODO: somehow write cache value to response
        // then send response
        return false;
    } else 
    {
        try
        {
            // TODO:  make direct request, 
            // get response body, then 
            response.sendRedirect( redirectMapping );
            return false;
        } catch ( IOException e )
        {
            e.printStackTrace();
        }
    }

    return false;

}

所以在我的问题堆积到天花板之前,我会寻求帮助 - 这个网站图标请求是如何在我的拦截器甚至对原始 URL 有裂缝之前偷偷溜进来的,为什么我不能在我的拦截器中获取原始 URL,并且鉴于 Chrome devtools 显示我正在进入 test2,输出如何来自 test1 servlet 而不是 test2 servlet?

FWIW,我在邮递员中得到了完全相同的行为。非常感谢您的帮助!

标签: springfilterinterceptor

解决方案


我在 SO 上阅读了另一个答案(对不起,我没有链接),它解决了不拦截对 /test 的初始获取请求的问题——它说拦截器只拦截发往控制器的请求,所以我需要一个映射到 /test 的控制器。在编写了一个快速控制器之后,拦截器现在正在拦截,正如人们所期望的那样。


推荐阅读