4

我无法让 ZK 会话超时发生,因为我们的应用程序每隔几分钟就轮询一次服务器以获取信息。触发此轮询的代码是 Javascript,它单击隐藏按钮,向服务器发送 onClick 事件。

你知道有什么方法可以告诉 ZK 这个轮询是自动的并且不应该影响会话超时计时器吗?

非常感谢。

-伊恩

4

2 回答 2

3

简短的回答是否定的。

长答案是,首先没有“ZK Session”。它只是 Servlet 规范定义的 HttpSession。其次,会话管理由 servlet Web 容器完成,因此会话超时计数器重置在请求传递给 ZK 处理之前很久就完成了。

于 2013-01-03T02:13:13.027 回答
3

一种解决方法是编写一个过滤器来检测请求是否是轮询请求,并在过滤器中记录“真实”请求的时间,然后如果长时间没有真实请求,则使会话无效。

样本:

测试.zul

<zk>
    <intbox id="ibx" value="1" />
    <timer delay="1000" id="pooltimer" repeats="true">
        <attribute name="onTimer"><![CDATA[
            ibx.setValue(ibx.getValue() + 1);
        ]]></attribute>
    </timer>
    <button label="click or invalidated in 20 seconds">
        <attribute name="onClick"><![CDATA[
            long lastRealRequest = (Long)Sessions.getCurrent().getAttribute("LAST_REAL_REQUEST");
            alert("only pooling request in "
                    + ((System.currentTimeMillis() - lastRealRequest) / 1000)
                    + " second(s)");
        ]]></attribute>
    </button>
</zk>

zk.xml

<zk>
    <session-config>
        <session-timeout>20</session-timeout>
    </session-config>
</zk>

在 web.xml 中过滤

<filter>
    <filter-name>requestFilter</filter-name>
    <filter-class>test.RequestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>requestFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

请求过滤器.java

package test;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;





public class RequestFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        Map param = req.getParameterMap();
        HttpSession sess = req.getSession();
        boolean isRealRequest = true;
        // here detect whether it is the poll request
        // initiate the LAST_REAL_REQUEST if the poll request is
        // the first request
        //
        // invalidate session if no real request within session timeout range
        for (Object key : param.keySet()) {
            if (key.toString().startsWith("cmd")
                && "onTimer".equals(((String[])param.get(key))[0])) {
                // not real request
                isRealRequest = false;
                // try get last real request time
                Long lastRealRequest = (Long)sess.getAttribute("LAST_REAL_REQUEST");
                if (lastRealRequest == null) {
                    System.out.println("init");
                    // init if no previous real request
                    lastRealRequest = System.currentTimeMillis();
                    sess.setAttribute("LAST_REAL_REQUEST", lastRealRequest);
                } else if ((System.currentTimeMillis() - lastRealRequest) > 20000) {
                    System.out.println("invalidate");
                    // invalidate session if only poll request for a long time
                    sess.invalidate();
                }
            }
        }

        // process request
        chain.doFilter(request, response);

        // update LAST_REAL_REQUEST if this is a real request
        if (isRealRequest) {
            // record last real request time
            sess.setAttribute("LAST_REAL_REQUEST", System.currentTimeMillis());
        }
    }
    @Override
    public void destroy() {}
}
于 2013-01-03T08:21:50.200 回答