servlet.Filter
(IPアドレスに基づいて)データベーステーブルでクライアントのユーザーIDを検索する実装があり、このデータを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
}
}
1つのクライアントからのロギングmyHttpSession.getCreationTime()
(タイムスタンプ)の結果は次のとおりです。
1343944955586
1343944955602
1343944955617
1343944955633
1343944955664
1343944955680
1343944955804
1343944955836
1343944955867
1343944955898
1343944955945
1343944955945
1343944956007
1343944956054
ご覧のとおり、ほとんどすべてのセッションが異なります。これらのタイムスタンプは、リクエストの間隔がどれだけ近いか(20ミリ秒から50ミリ秒)の良いアイデアにもなります。
すべてのクライアント側アプリケーションを再設計して、最初に別の要求を送信する前に少なくとも1つの応答を受け取るようにすることはできないので、フィルターでそれを実行したいと思います。
また、後続のリクエストを単に失敗させたくはありません。それらを処理する方法を見つけたいと思います。
質問
最初のリクエストからセッションが確立されるまで、同じクライアント(IPアドレス)からの後続のリクエストを「リンボ」に入れる方法はありますか?
HttpSession
そして、それを管理した場合、後で電話をかけたときに正しいもの(ユーザーデータを添付したもの)を取得するにはどうすればよいaSubsequentRequest.getSession()
ですか?リクエストにセッションを割り当てることはできないと思いますが、間違っている可能性があります。
たぶん、これを完全に回避するためのより良い方法がいくつかあります。基本的に、このフィルターが2秒以内にルックアップクエリを不必要に10〜20回実行しないようにします。