0

Im implementing a websocket server in grails and im getting error on client side connecting to it but only in production mode. This is the error im getting:

WebSocket connection to 'ws://localhost:8080/myApp/websocketDoc' failed: Error during WebSocket handshake: Unexpected response code: 404

Everything works fine in development mode.

I have a class in my src/groovy

package myApp;

import java.util.HashMap;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpoint;

import org.codehaus.groovy.grails.web.json.JSONObject;
import org.codehaus.groovy.grails.web.json.JSONArray;

import org.codehaus.groovy.grails.web.util.WebUtils;

import grails.util.Environment;

@WebListener
@ServerEndpoint("/websocketDoc")
public class WebsocketServletContextListener implements ServletContextListener {

private static final JSONArray jsonOpenedDocuments = new JSONArray();

@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    final ServerContainer serverContainer = (ServerContainer) servletContextEvent.getServletContext()
                                                .getAttribute("javax.websocket.server.ServerContainer");

    try {
        if (Environment.current == Environment.DEVELOPMENT) {
            serverContainer.addEndpoint(WebsocketServletContextListener)
        }

    } catch (DeploymentException e) {
        e.printStackTrace();
    }
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
@OnOpen
public void handleOpen() {
    System.out.println("Client is now connected.");
}
@OnMessage
public String handleMessage(String requestStr, Session userSession) {


    return "msg";
}
@OnClose
public void handeClose(Session userSession) {
    System.out.println("Client is now disconnected. id:" + userSession.id);
}
@OnError
public void handleError(Throwable t) {
    t.printStackTrace();
}

}

In my dependencies, BuilConfig.groovy i have:

dependencies {
    runtime 'mysql:mysql-connector-java:5.1.22'

    compile 'c3p0:c3p0:0.9.1.2'

    bundle('javax.websocket:javax.websocket-api:1.1') {
        export = false
    }

}

To add listener to the web.xml i have the following script in /scripts:

import groovy.xml.StreamingMarkupBuilder

eventWebXmlEnd = {String tmpfile ->
def root = new XmlSlurper().parse(webXmlFile)
root.appendNode {
   'listener' {
       'listener-class' (
           'myApp.WebsocketServletContextListener'
       )
    }
}

webXmlFile.text = new StreamingMarkupBuilder().bind {
    mkp.declareNamespace(
            "": "http://java.sun.com/xml/ns/javaee")
    mkp.yield(root)
}
}

In the client side i get the error in the following line:

var webSocketUrl = "${createLink(uri: '/websocketDoc', absolute: true).replaceFirst(/https/, /wss/).replaceFirst(/http/, /ws/)}";

var webSocket = new WebSocket(webSocketUrl); // getting 404 error when running in production mode

Any clue why this only works in development mode? Thanks

  • yes the clue is the error message does not tally up with the new Websocket connection line you are showing you are suggesting that the url is replaced from https to wss and yet the backend error shows ws://localhost:8080 so two issues one the host 2nd the protocol appear to be different therefore I would enable console.log in the js parts to see what that url is and what else is actually triggering connection since don't think its what you think it is – V H Nov 22 '17 at 15:15
  • In my local server is http://localhost:8080/myApp/websocketDoc, so the https part does nothing on that line, it replaces http to ws. When i put it online server it replaces the protocol https to wss, that look ok i guess – Rui Ferreira Nov 22 '17 at 15:26
  • but the backend error you are showing which i presume is for prod still shows ws and localhost - which is why it works locally and not on production cos that line isn't probably triggering the ws connection something else is. If that error is from the prod when u trigger it – V H Nov 22 '17 at 15:57
  • runing the grails app in production mode (local server) i get that error ws://localhost. In production mode (online) e get the error: WebSocket connection to 'wss://myWebapp.com/websocketDoc' failed: Error during WebSocket handshake: Unexpected response code: 404 – Rui Ferreira Nov 22 '17 at 16:20
  • that is cos you are not in real production so either run it properly in a local tomcat by exporting out war file or add the same block for production here `if (Environment.current == Environment.PRODUCTION) { serverContainer.addEndpoint(WebsocketServletContextListener) } ` but then when you get to run in tomcat you will need to take it out again – V H Nov 22 '17 at 16:39
  • if i put that: if (Environment.current == Environment.PRODUCTION) { serverContainer.addEndpoint(WebsocketServletContextListener) }. i get this error when deploying it in tomcat org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext javax.websocket.DeploymentException: Multiple Endpoints may not be deployed to the same path [/websocketDoc] : existing endpoint was class myApp.WebsocketServletContextListener and new endpoint is class myApp.WebsocketServletContextListener ... – Rui Ferreira Nov 22 '17 at 16:53
  • I cant recall exactly but I would suggest trying to run it in a local tomcat ir you are trying to imitate production I hardly see the point if it is working under grails run-app and you are just testing - test it properly to know for sure – V H Nov 22 '17 at 17:42
  • Okay i installed a local tomcat and deployed it and it works perfectly... dont know why it dont work on server tomcat. Tomcat same version 8.0.33 – Rui Ferreira Nov 23 '17 at 11:45
  • I did say do it in tomcat - this was cos I had falled down that path previously with it all I think hence the advice - as I suggested previously the grails run-war is not actually a proper tomcat. Tomcat itself comes equipped and can map the serverEndpoint cos that is where it is going wrong and why you add the stuff you do in dev mode. – V H Nov 23 '17 at 17:35
  • I mean i did it in tomcat and it works perfectly, it dont work when access it online wss://mywebapp.com/websocketDoc. I think it may be a apache proxy problem that i need to configure on server. – Rui Ferreira Nov 24 '17 at 09:04

0 Answers0