jsf - 使用 org.omnifaces.cdi.ViewScoped 时,我的 javax.servlet.Filter 在单个页面视图上同时接收到 GET 和 POST
问题描述
我用于记录页面视图的 servletfilter 正在接收带有单个页面请求的 GET 和 POST。我将其追溯到在页面支持 bean 上使用 Omnifaces ViewScope。
@Named
@org.omnifaces.cdi.ViewScoped
我碰巧注意到我的日志文件中带有精确时间戳的双页浏览量。使用以下简化版本进行调试,在单个页面请求上,doFilter 执行两次,第一次是 GET,URL 是我正在浏览的 URL。然后 doFilter 再次执行,它是一个 POST 并且 URL 是我来自的页面。如果我刷新页面,我会看到一个 GET,然后是一个 POST 到同一页面。如果我使用javax.faces.view.ViewScoped
,只有 GET 请求进来。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
System.out.println(new java.util.Date() + " " + ((HttpServletRequest) request).getMethod() + " " + httpRequest.getServletPath());
chain.doFilter(request, response);
}
例如,如果我正在查看 http://localhost:8080/myApp/page1.xhtml 并将 url 更改为 page2.xhtml
过滤器会写出
Wed Aug 26 12:17:04 EDT 2020 GET /page2.xhtml
Wed Aug 26 12:17:04 EDT 2020 POST /page1.xhtml
也许是设计使然?. 但我只想记录用户正在浏览的页面,而不是他们来自的页面。是不是很简单?:
if(((HttpServletRequest) request).getMethod().equalsIgnoreCase("GET")){
//Write to actual log file
}
还是我使用omnifaces viewscope错了?
解决方案
这确实是设计使然。前一页上的 POST 基本上发送一个页面已卸载的信号,因此背后的逻辑@ViewScoped
知道它必须立即销毁 JSF 视图状态和物理 bean。
另请参阅文档:
...这个 CDI 视图范围注释将保证
@PreDestroy
在浏览器卸载时也会调用带注释的方法。这个技巧是由navigator.sendBeacon
. 对于不支持的浏览器navigator.sendBeacon
,它将回退到同步 XHR 请求。
当您想在过滤器中检测它们时,您可以使用ViewScopeManager#isUnloadRequest()
.
if (!ViewScopeManager.isUnloadRequest(request)) {
// Write to actual log file.
}
chain.doFilter(request, response); // Ensure that this just continues!
诚然,这确实记录得不够清楚,我会在下一个版本中记住这一点。
推荐阅读
- excel - Power Query - 特定文本的累积计数器(索引)
- react-native - 使用 React native 聚焦 WebView 中的输入
- cypress - 如何使用不同的 Cypress.env() 变量进行 Circle 测试?
- frontend - 在生产中更新现有的 SPA 项目(维护模式?)
- reactjs - react -npm run build 生成一个空页面
- python - 如何在python列中使用多索引访问数据
- excel - 如何从一个excel表中获取数据并将其添加到不同表中的匹配行?
- c# - 假脱机由 Observable.FromEvent 生成的正在进行的项目
- r - 用R计算多个多边形之间的最小距离
- javascript - Internet Explorer 中的 Angular 无效日期错误