首页 > 解决方案 > 在 java websocket 中添加 servlet 过滤器时,会话在指定时间后没有超时

问题描述

我的一个 web 应用程序中有 websocket,用于填充通知消息。整个应用程序是一个ear 文件,其中有多个war 文件,这个websocket 端点是一个war 文件。

它包含以下内容:

    @ServerEndpoint(value = "/message", configurator = WebSocketConfigurator.class)
    public class WebsocketEndpoint {
    @OnOpen
    public void onOpen(Session session){

    }
    @OnClose
    public void onClose() {

    }

    @OnError
    public void error(Session session, Throwable throwable) {

    }

    @OnMessage
    public void handleMessage(String message, final Session session) {
        synchronized (session) {
            if (session != null && session.isOpen()) {
                int count = 2;                                
                session.getAsyncRemote().sendText("" + count);
                session.setMaxIdleTimeout(-1);
            }
        }
    }

}

public class WebSocketConfigurator extends ServerEndpointConfig.Configurator  {
    private boolean isValidHost;
    @Override
    public boolean checkOrigin(String originHeaderValue) {
    try {
        URL url = new URL(originHeaderValue);
        String hostName = url.getHost();
        isValidHost = Utils.isValidHostName(hostName);
    } catch (Exception ex){
        logger.error("Error in check checkOrigin for websocket call: "+ex.getMessage());
    }
    return isValidHost;
}
}

我在第一次登录时调用端点,握手将发生并获取消息,然后每 2 分钟它将调用一次以获取消息,仅没有握手,因为握手已经存在 ui 如下:

var websocketUrl = new WebSocket("ws://localhost:7001/example/message");
webSocket.onopen = function() {
webSocket.send('');
}
var interval=  setInterval(function() {
        'pollMessage()' 
    }, 120*1000);

    function  pollMessage(){
        if(wsEndPoint.readyState==1){
            wsEndPoint.send('');
        }
        if(wsEndPoint.readyState ==2 || wsEndPoint.readyState==3){
            wsEndPoint.close();
            clearInterval(interval);
        }
        wsEndPoint.onmessage = function(message){ 
            alert(message);
        }
    }



@WebServlet(urlPatterns = {"/message"})
public class MessageWebsocketServlet extends HttpServlet
{
}

以上工作正常,没有任何问题。

但我想对安全调用进行身份验证。

所以我添加了网络过滤器

@WebFilter(urlPatterns = {"/message"}, filterName = "AuthFilter",initParams = {
        @WebInitParam(name = "authorizationEnabled", value = "false")
})
@ServletSecurity(httpMethodConstraints = {@HttpMethodConstraint(value = "GET")})
public class MessageWebsocketServletFilter implements Filter{

 private FilterConfig config = null;

@Override
public void init(FilterConfig config) throws ServletException {
}
 @Override
public void doFilter(ServletRequest req, ServletResponse res,
                     FilterChain chain)
        throws ServletException, IOException {
//authentication logic goes here and it involved cross origin check and 
}
@Override
public void destroy() {
    config.getServletContext().log("Destroying SessionCheckerFilter");
}

}

我们已将 30 分钟配置为会话超时,并且当用户登录并空闲超过 30 分钟时添加上述过滤器后,应用程序不会导致会话超时。

任何指针都会对我有很大帮助。

标签: javascriptservletsservlet-filtersservlet-3.0java-websocket

解决方案


精简版:

据我所知,这是因为线session.setMaxIdleTimeout(-1);

长版:

打开 websocket 连接时,客户端会进行握手。遵循 websocket 圣经(RFC 6455 第 1.3 节),握手从HTTP通信开始。

但是,一旦握手成功,通信就会切换到另一个协议,如下所述:

HTTP/1.1 101 交换协议

升级:websocket

连接:升级

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

通信不再是 HTTP。据我所知,Java Servlet 只处理 HTTP 通信。因此,任何有关 servlet 的配置都不会影响 websocket 配置。


推荐阅读