我有一个servlet.Filter
实现,它在数据库表中查找客户端的用户 ID(基于 IP 地址),它将这些数据附加到一个HttpSession
属性。过滤器在收到来自客户端的请求时执行此操作,而没有定义HttpSession
.
换句话说,如果请求没有附加会话,过滤器将:
- 为客户端创建会话
- 对用户 ID 进行数据库查找
- 将用户 ID 作为会话属性附加
如果“无会话”客户端的请求之间有一段时间,这一切都可以正常工作。
但是,如果一个“无会话”客户端在几毫秒内发送 10 个请求,我最终会得到 10 个会话和 10 个数据库查询。它仍然“有效”,但出于资源原因,我不喜欢所有这些会话和查询。
我认为这是因为请求非常接近。当“无会话”客户端发送请求并在发送另一个请求之前获得响应时,我没有这个问题。
我的过滤器的相关部分是:
// some other imports
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
public class QueryFilter implements Filter {
private QueryRunner myQueryRunner;
private String myStoredProcedure;
private String myPermissionQuery;
private MapHandler myMapHandler;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
Config config = Config.getInstance(filterConfig.getServletContext());
myQueryRunner = config.getQueryRunner();
myStoredProcedure = config.getStoredProcedure();
myUserQuery = filterConfig.getInitParameter("user.query");
myMapHandler = new MapHandler();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException {
HttpServletRequest myHttpRequest = (HttpServletRequest) request;
HttpServletResponse myHttpResponse = (HttpServletResponse) response;
HttpSession myHttpSession = myHttpRequest.getSession(false);
String remoteAddress = request.getRemoteAddr();
// if there is not already a session
if (null == myHttpSession) {
// create a session
myHttpSession = myHttpRequest.getSession();
// build a query parameter object to request the user data
Object[] queryParams = new Object[] {
myUserQuery,
remoteAddress
};
// query the database for user data
try {
Map<String, Object> userData = myQueryRunner.query(myStoredProcedure, myMapHandler, queryParams);
// attach the user data to session attributes
for (Entry<String, Object> userDatum : userData.entrySet()) {
myHttpSession.setAttribute(userDatum.getKey(), userDatum.getValue());
}
} catch (SQLException e) {
throw new ServletException(e);
}
// see below for the results of this logging
System.out.println(myHttpSession.getCreationTime());
}
// ... some other filtering actions based on session
}
}
以下是myHttpSession.getCreationTime()
来自 ONE 客户端的日志记录(时间戳)结果:
1343944955586
1343944955602
1343944955617
1343944955633
1343944955664
1343944955680
1343944955804
1343944955836
1343944955867
1343944955898
1343944955945
1343944955945
1343944956007
1343944956054
正如你所看到的,几乎所有的会话都是不同的。这些时间戳还可以很好地了解请求之间的间隔距离(20ms - 50ms)。
我无法重新设计所有客户端应用程序以确保它们在最初发送另一个请求之前至少获得一个响应,所以我想在我的过滤器中这样做。
另外,我不想只是让后续请求失败,我想找出一种处理它们的方法。
问题
有没有办法将来自同一客户端(IP 地址)的后续请求放入“limbo”,直到从第一个请求建立会话?
而且,如果我能做到这一点,当我之后打电话时,我怎样才能得到正确
HttpSession
的(我附加用户数据的那个)aSubsequentRequest.getSession()
?我认为我不能为请求分配会话,但我可能是错的。
也许有一些更好的方法可以完全解决这个问题。我基本上只是想阻止此过滤器在 2 秒的时间段内不必要地运行查找查询 10 到 20 次。