Javax WebSockets 不适用于 programmattic Tomcat 7 实例化
Javax WebSockets won't work with programmattic Tomcat 7 instantiation
这是我正在尝试做的事情:
- 以编程方式设置 Tomcat 7 服务器 - 可以 使用简单的 servlet。我仅从代码中定义 Tomcat 的端点,文件系统上没有设置或路由器(这是一个约束)。
- 让上述 Tomcat 服务器包含使用 Javax Websockets API (1.1) 的 websocket 服务器端点 - 不起作用.
我的app/server入口点:
package com.myapp;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
import org.apache.catalina.startup.Tomcat;
public class App
{
public static void main(String[] args) throws LifecycleException
{
int port = 8080;
Tomcat webServer = new Tomcat();
webServer.setPort(port);
webServer.setHostname("localhost");
String appBase = ".";
webServer.getHost().setAppBase(appBase);
File docBase = new File(System.getProperty("java.io.tmpdir"));
Context context = webServer.addContext("", docBase.getAbsolutePath());
// both MyServlet and MyFilter exist and work.
Class servletClass = MyServlet.class;
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
context.addServletMapping("/my-servlet/*", servletClass.getSimpleName());
Class filterClass = MyFilter.class;
FilterDef myFilterDef = new FilterDef();
myFilterDef.setFilterClass(filterClass.getName());
myFilterDef.setFilterName(filterClass.getSimpleName());
context.addFilterDef(myFilterDef);
FilterMap myFilterMap = new FilterMap();
myFilterMap.setFilterName(filterClass.getSimpleName());
myFilterMap.addURLPattern("/my-servlet/*");
context.addFilterMap(myFilterMap);
webServer.start();
webServer.getServer().await();
}
}
我的 websocket 服务器端点 class:
package com.myapp;
import java.nio.ByteBuffer;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/web-socket/")
public class WebSocket
{
@OnOpen
public void onOpen()
{
System.out.println("Open Connection ...");
}
@OnMessage
public static void onTextMessage(Session session, String msg) {
System.out.println("On Message for Web Socket");
}
@OnMessage
public void onBinaryMessage(Session session, ByteBuffer msg){
System.out.println("On Message for Web Socket");
}
@OnMessage
public void onPongMessage(Session session, PongMessage pMsg) {
System.out.println("On Message for Web Socket");
}
@OnClose
public void onClose(Session session) {
System.out.println("Connection Close for Web Socket");
}
@OnError
public void onError(Throwable e)
{
e.printStackTrace();
}
}
我正在使用 Maven,我将 WebSocket API 和 <scope>provided</scope>
包括在一起,正如我在其他问题中看到的那样,这是其他问题的根源。
当我 运行 服务器时,我可以成功访问 my-servlet
端点(当然是作为网页),但是当我尝试创建 WS 对象时,只需在浏览器的使用 var webSocket = new WebSocket("ws://localhost:8080/web-socket")
的开发控制台,它说它无法到达端点:
WebSocket connection to 'ws://localhost:8080/web-socket' failed: Error during WebSocket handshake: Unexpected response code: 404
我的问题:我错过了什么? 错误消息(来自 Chrome)表明端点未注册(因此是 404)。如何注册 websocket ServerEndpoint?谢谢!
编辑:
这是我对 MyServlet
class 的实现:
package com.myapp;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet
{
@Override
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) throws IOException
{
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write("Works...");
resp.getWriter().flush();
resp.getWriter().close();
}
}
这是我对 MyFilter
的实现:
package com.myapp;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class MyFilter implements Filter
{
@Override
public void init(FilterConfig filterConfig)
{
// ...
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("myHeader", "myHeaderValue");
chain.doFilter(request, httpResponse);
}
@Override
public void destroy()
{
// ...
}
}
试试这个来手动添加网络套接字端点:
String serverContainerClass = ServerContainer.class.getName();
//should be "javax.websocket.server.ServerContainer", if not, some external package could have hogged the implementation
final ServerContainer serverContainer = (ServerContainer) context.getServletContext().getAttribute(serverContainerClass);
try
{
serverContainer.addEndpoint(WebSocket.class);
}
catch (DeploymentException e)
{
TraceWriter.Error(this, "Failed to initialize websocket", e);
}
您应该在将 servlet 添加到上下文后放置此代码
这是我正在尝试做的事情:
- 以编程方式设置 Tomcat 7 服务器 - 可以 使用简单的 servlet。我仅从代码中定义 Tomcat 的端点,文件系统上没有设置或路由器(这是一个约束)。
- 让上述 Tomcat 服务器包含使用 Javax Websockets API (1.1) 的 websocket 服务器端点 - 不起作用.
我的app/server入口点:
package com.myapp;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
import org.apache.catalina.startup.Tomcat;
public class App
{
public static void main(String[] args) throws LifecycleException
{
int port = 8080;
Tomcat webServer = new Tomcat();
webServer.setPort(port);
webServer.setHostname("localhost");
String appBase = ".";
webServer.getHost().setAppBase(appBase);
File docBase = new File(System.getProperty("java.io.tmpdir"));
Context context = webServer.addContext("", docBase.getAbsolutePath());
// both MyServlet and MyFilter exist and work.
Class servletClass = MyServlet.class;
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
context.addServletMapping("/my-servlet/*", servletClass.getSimpleName());
Class filterClass = MyFilter.class;
FilterDef myFilterDef = new FilterDef();
myFilterDef.setFilterClass(filterClass.getName());
myFilterDef.setFilterName(filterClass.getSimpleName());
context.addFilterDef(myFilterDef);
FilterMap myFilterMap = new FilterMap();
myFilterMap.setFilterName(filterClass.getSimpleName());
myFilterMap.addURLPattern("/my-servlet/*");
context.addFilterMap(myFilterMap);
webServer.start();
webServer.getServer().await();
}
}
我的 websocket 服务器端点 class:
package com.myapp;
import java.nio.ByteBuffer;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/web-socket/")
public class WebSocket
{
@OnOpen
public void onOpen()
{
System.out.println("Open Connection ...");
}
@OnMessage
public static void onTextMessage(Session session, String msg) {
System.out.println("On Message for Web Socket");
}
@OnMessage
public void onBinaryMessage(Session session, ByteBuffer msg){
System.out.println("On Message for Web Socket");
}
@OnMessage
public void onPongMessage(Session session, PongMessage pMsg) {
System.out.println("On Message for Web Socket");
}
@OnClose
public void onClose(Session session) {
System.out.println("Connection Close for Web Socket");
}
@OnError
public void onError(Throwable e)
{
e.printStackTrace();
}
}
我正在使用 Maven,我将 WebSocket API 和 <scope>provided</scope>
包括在一起,正如我在其他问题中看到的那样,这是其他问题的根源。
当我 运行 服务器时,我可以成功访问 my-servlet
端点(当然是作为网页),但是当我尝试创建 WS 对象时,只需在浏览器的使用 var webSocket = new WebSocket("ws://localhost:8080/web-socket")
的开发控制台,它说它无法到达端点:
WebSocket connection to 'ws://localhost:8080/web-socket' failed: Error during WebSocket handshake: Unexpected response code: 404
我的问题:我错过了什么? 错误消息(来自 Chrome)表明端点未注册(因此是 404)。如何注册 websocket ServerEndpoint?谢谢!
编辑:
这是我对 MyServlet
class 的实现:
package com.myapp;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet
{
@Override
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) throws IOException
{
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write("Works...");
resp.getWriter().flush();
resp.getWriter().close();
}
}
这是我对 MyFilter
的实现:
package com.myapp;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class MyFilter implements Filter
{
@Override
public void init(FilterConfig filterConfig)
{
// ...
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("myHeader", "myHeaderValue");
chain.doFilter(request, httpResponse);
}
@Override
public void destroy()
{
// ...
}
}
试试这个来手动添加网络套接字端点:
String serverContainerClass = ServerContainer.class.getName();
//should be "javax.websocket.server.ServerContainer", if not, some external package could have hogged the implementation
final ServerContainer serverContainer = (ServerContainer) context.getServletContext().getAttribute(serverContainerClass);
try
{
serverContainer.addEndpoint(WebSocket.class);
}
catch (DeploymentException e)
{
TraceWriter.Error(this, "Failed to initialize websocket", e);
}
您应该在将 servlet 添加到上下文后放置此代码