Websocket - httpSession returns null

2019-01-27 14:12发布

问题:

I would like to make the connection between a websocket handshake \ session to a HttpSession object.

I've used the following handshake modification:

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
@Override
public void modifyHandshake(ServerEndpointConfig config, 
                            HandshakeRequest request, 
                            HandshakeResponse response)
{
    HttpSession httpSession = (HttpSession)request.getHttpSession();
    config.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}

As mentioned in this post: Accessing HttpSession from HttpServletRequest in a Web Socket @ServerEndpoint

Now, For some reason on the hand shake, the (HttpSession)request.getHttpSession() returns null all the time.

here is my client side code:

<!DOCTYPE html>
<html>
<head>
<title>Testing websockets</title>
</head>
<body>
<div>
    <input type="submit" value="Start" onclick="start()" />
</div>
<div id="messages"></div>
<script type="text/javascript">
    var webSocket = 
        new WebSocket('ws://localhost:8080/com-byteslounge-websockets/websocket');

    webSocket.onerror = function(event) {
        onError(event)
    };

    webSocket.onopen = function(event) {
        onOpen(event)
    };

    webSocket.onmessage = function(event) {
        onMessage(event)
    };

    function onMessage(event) {
        document.getElementById('messages').innerHTML 
            += '<br />' + event.data;
    }

    function onOpen(event) {
        document.getElementById('messages').innerHTML 
            = 'Connection established';
    }

    function onError(event) {
        alert(event.data);
    }

    function start() {
        webSocket.send('hello');
        return false;
    }
</script>
</body>
</html>

Any ideas why no session is created ? Thanks

回答1:

This is intended behaviour, but I agree it might be confusing. From the HandshakeRequest.getHttpSession javadoc:

/**
 * Return a reference to the HttpSession that the web socket handshake that 
 * started this conversation was part of, if the implementation
 * is part of a Java EE web container.
 *
 * @return the http session or {@code null} if either the websocket
 * implementation is not part of a Java EE web container, or there is
 * no HttpSession associated with the opening handshake request.
 */

Problem is, that HttpSession was not yet created for your client connection and WebSocket API implementation just asks whether there is something created and if not, it does not create it. What you need to do is call httpServletRequest.getSession() sometime before WebSocket impl filter is invoked (doFilter(...) is called).

This can be achieved for example by calling mentioned method in ServletRequestListener#requestInitalized or in different filter, etc..



回答2:

Here is an impl for Pavel Bucek's Answer, after adding it, i got my session

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class RequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // TODO Auto-generated method stub

    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        ((HttpServletRequest) sre.getServletRequest()).getSession();
    }

}


回答3:

Building on @pavel-bucek 's answer, I wrote a simple HttpSessionInitializerFilter servlet filter.

Just download the jar from the "Releases" page and save it anywhere in the classpath, then add the following snippet to your web.xml descriptor (modify the url-pattern as needed):

<filter>
  <filter-name>HttpSessionInitializerFilter</filter-name>
  <filter-class>net.twentyonesolutions.servlet.filter.HttpSessionInitializerFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>HttpSessionInitializerFilter</filter-name>
  <url-pattern>/ws/*</url-pattern>
</filter-mapping>


回答4:

first: create a new class

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener

public class RequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
    }

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        ((HttpServletRequest)servletRequestEvent.getServletRequest()).getSession();
    }
}

and then add the "ServletComponentScan" annotation on the App main:

@SpringBootApplication

@ServletComponentScan

public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}