spring - 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 中的网络选项卡似乎建议:
我被重定向到 test2,但只有在插入了对 favicon 的请求之后(无论出于何种神秘原因),但如图所示,输出显然是 test1,而不是 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,我在邮递员中得到了完全相同的行为。非常感谢您的帮助!
解决方案
我在 SO 上阅读了另一个答案(对不起,我没有链接),它解决了不拦截对 /test 的初始获取请求的问题——它说拦截器只拦截发往控制器的请求,所以我需要一个映射到 /test 的控制器。在编写了一个快速控制器之后,拦截器现在正在拦截,正如人们所期望的那样。
推荐阅读
- sql - 仅通过触发器对插入的行运行更新语句
- angular - 将 AWS MediaLive 与 Angular 结合使用
- java - AnyLogic - selectOutput5 中最后一个出口端口的自定义条件
- javascript - 在 React 中让异步钩子相互等待
- java - 构造函数声明后构造函数对象发生变化
- python - 无论如何,是否可以将在 vscode 中调试的 jupyter notebook 中的 ipython matplotlib 图形渲染为 py 文件?
- sql - 另一个字段中包含的属性值的 SQL 连接
- python-3.x - 在 Jupyter 笔记本中显示 HTML 后隐藏空格
- matlab - 如何使用 MATLAB 正确进行频率带通滤波器?
- swift - 与 UIActivityViewController 共享内容