Websocket - httpSession returns null
Asked Answered
R

4

16

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

Renunciation answered 27/11, 2013 at 10:58 Comment(3)
I hope keeping the client side code in Servlet or jsp instead of plain html might help, since session object will be initiated in those cases. I haven't tried though.Brilliantine
I have this issue only if I access my web app through a reverse proxy (nginx). On direct access, getHttpSession does not return null. What is different when using nginx?Buddleia
Found my issue: was mixing "localhost" and "127.0.0.1" in URLs. The http session id was not sent for the other host name I guess.Buddleia
H
11

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..

Heckman answered 29/11, 2013 at 14:33 Comment(1)
How do you get the httpservletRequest object from the ServletRequestEvent pServletRequestEvent object passed to the requestInitalized method?Leninism
J
9

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();
    }

}
Japha answered 16/12, 2015 at 20:35 Comment(1)
Since I usually disable Jar Scanning for a faster startup, I had to also add a listener to web.xml, e.g. <listener><listener-class>path.to.RequestListener</listener-class></listener> in order to register the @WebListener without relying on the annotations.Symbiosis
S
1

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>
Symbiosis answered 13/7, 2017 at 21:44 Comment(0)
U
0

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);
    }
}
Uhl answered 25/8, 2017 at 3:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.