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