I create a sample webapp using Guice-servlets and websocket in tomcat, now once guice filter is used websocket stop working
In my web.xml, i initialized the Guiceservlet using GuiceBasedListener
<web-app>
<listener>
<listener-class>test.GuiceBasedListener</listener-class>
</listener>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
GuieBasedListener
Code which binds all request /*
to MyDispatcher
public class GuiceBasedListener extends GuiceServletContextListener {
protected Injector getInjector() {
return Guice.createInjector( new ServletModule() {
@Override
protected void configureServlets() {
bind(MyDispatcher.class).asEagerSingleton();
serve("/*").with(MyDispatcher.class);//////IMPORTANT LINE//
}
});}}
MyDispatcher
code which just respond with a String
public class MyDispatcher extends HttpServlet {
@Inject private Injector injector;
public MyDispatcher() {}
public void service(ServletRequest req, ServletResponse resp) throws IOException, ServletException {
resp.getOutputStream().print("SUCCESS:" + req);
}
}
Also i have a @ServerEndPoint for Websocket
@ServerEndpoint(value = "/websocket/chat2")
public class WebSocket{
....
@OnOpen
public void start(Session session) {
System.out.println("Staring:"+this);
}
....
}
Observations:
SUCCESS
Now if i comment serve("/*").with(MyDispatcher.class);
basically if we switch off guice routing the websocket starts to work
If i switch off guice-servlet but add a servlet mapping in web.xml like below websocket still works
< servlet-mapping >
< servlet-name > HelloWorld< / servlet-name >
< url-pattern > /* < / url-pattern >
< / servlet-mapping >
What am i missing or doing wrongly?
EDIT:
Observation-conti:
FILTER
.public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.getOutputStream().print("FILTER"); }
and changed my web.xml to
<web-app>
<filter>
<filter-name>myFilter</filter-name>
<filter-class>test.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Now hitting the http://localhost:8080/app/x
return FILTER
as expected.
But trying to connect with websocket fail as the request shows something like this.
I also noticed that as i change the String MyFilter
return the content length in response changes , which meaning the request reached MyFilter
before tomcat handled it for websocket.
I changed the web.xml to below and guice and websocket are working fine now.. so i think Guice is not honoring the WsFilter that registered after the GuiceFilter
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.apache.tomcat.websocket.server.WsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
TOMCAT 8.0, Window 7, Java 1.7 , Guice 4.0, Guice-servlet-4.0
That also looks like a Guice issue to me (as already mentioned in comments). Using servlets and WebSockets in same application should not be a problem, even with a servlet mapping that covers /*
.
2 relevant things about servlets and filters:
So, if WsFilter is first, it will intercept the request first, then check if it's a WebSocket upgrade request.
If it's indeed a WebSocket connection, the filter will not pass it on to the rest of the chain.
If it's another type of request (GET, POST...), it will pass it on, and then Guice will do its thing.
(so you found a first solution here)
If Guice filter is first, AND you use serve("/*")...
, then it breaks your WS.
If you comment out serve("/*")...
, then it does not matter if Guice filter is first or not, WsFilter can even be absent: your WS can be reached (which establishes GuiceFilter alone is OK).
So Guice has its own "layer of interception" above servlet mappings, and I think that's what breaks WebSockets. I don't know if there is a bug or anything to fix in Guice (I mean probably, but don't know what exactly), but you can specify exceptions to Guice (unlike servlet mappings in web.xml
).
Replace this:
serve("/*").with(TestServlet.class);
with this:
serveRegex("/(?!websocket/).*").with(TestServlet.class);
// Regex that accepts /.* but excludes /websocket/.*
With that, you can keep the servlet mapping on /*
, and remove WsFilter
as it is not needed. (Tested, works for me)
So that's a second solution, that has the advantage that it also allows to specify exceptions for non-WebSocket stuff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With