tomcat - 重新连接的 websocket 无法连接到服务器,FacesContext.getCurrentInstance() 被解析为 null
问题描述
我有一个安装了以下依赖项的普通 Tomcat 8.5.47。
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.9</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>2.4.8.Final</version>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
CDI 似乎工作正常,或者至少,我在迁移@ManagedBean
s 到@Named
. 安装了 CDI 意味着我可以注入 aPushContext
并将一些消息从服务器发送到客户端。
我声明了一个简单的bean
@ApplicationScoped
@Named("ButtonController")
public class ButtonController implements Serializable {
@Inject
@Setter
@Push(channel = "someChannel")
private PushContext _someChannel;
public void onPress() {
_someChannel.send("...");
}
}
和 JSF 模板中的通道
<f:websocket channel="someChannel"
onmessage="_onmessage"
onopen="_onopen"
onclose="_onclose"
/>
回调打印控制台消息。
<h:outputScript>
function _onopen() {
console.log('_onopen')
}
</h:outputScript>
当我加载其中定义了套接字的页面时,正在打开套接字并在控制台中显示一条消息。
_onopen
然后我转到浏览器中的网络选项卡,看到大量请求正在主动发送。这是其中之一。
Request URL: ws://localhost:10000/bg/javax.faces.push/someChannel?55685979-de8b-4a27-b497-f726cbea02ca
Request Method: GET
Status Code: 101
Connection: upgrade
Date: Tue, 16 Jun 2020 10:46:22 GMT
Sec-WebSocket-Accept: L4F6dcI3YMvkvsRhG7IyGCWYxuI=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Upgrade: websocket
我认为这是由于重新连接的 websocket 无法重新建立连接。我转到服务器日志,确实看到这个异常一遍又一遍地重复。
16-Jun-2020 13:15:54.153 SEVERE [http-nio-10000-exec-2] org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error reading request, ignored
java.lang.NullPointerException
at com.sun.faces.cdi.CdiUtils.getBeanReferenceByType(CdiUtils.java:230)
at com.sun.faces.cdi.CdiUtils.getBeanReference(CdiUtils.java:213)
at com.sun.faces.push.WebsocketSessionManager.getInstance(WebsocketSessionManager.java:240)
at com.sun.faces.push.WebsocketEndpoint.onOpen(WebsocketEndpoint.java:88)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init(WsHttpUpgradeHandler.java:133)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:856)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
我调试堆栈跟踪并对这种方法感到困惑。
public static <T> T getBeanReference(Class<T> type, Annotation... qualifiers) {
return type.cast(getBeanReferenceByType(Util.getCdiBeanManager(FacesContext.getCurrentInstance()), type, qualifiers));
}
whereFacesContext.getCurrentInstance()
返回null
解析null
导致异常的 CDI 管理器。这是完全可以理解的,因为在这意味着 CDI 配置不正确或我遗漏了一些东西的过程中没有触及 JSF 工件。
引起我注意的另一件事WebsocketSessionManager
是检索方式以及沿途的评论。
/**
* Internal usage only. Awkward workaround for it being unavailable via @Inject in endpoint in Tomcat+Weld/OWB.
*/
static WebsocketSessionManager getInstance() {
if (instance == null) {
instance = getBeanReference(WebsocketSessionManager.class);
}
return instance;
}
任何轻推都非常受欢迎。谢谢。
更新:
我注意到com.sun.faces.config.FacesInitializer
寻找
org.glassfish.tyrus.servlet.TyrusServletContainerInitializer
在这一点
Class<?> tyrusInitializerClass;
try {
tyrusInitializerClass = cl.loadClass("org.glassfish.tyrus.servlet.TyrusServletContainerInitializer");
} catch (ClassNotFoundException cnfe) {
// No possibility of WebSocket.
return;
}
我想知道我是否需要这种依赖。
更新 2:
我发现这些似乎相关的问题:
解决方案
推荐阅读
- python - 如何找出数据框中的一行是否已存在于单独的数据框中?
- sql-server - 更新和替换查询
- php - Laravel Eloquent 查询仅从数据库表中返回一行
- android - 无法滚动浏览活动
- php - Codeigniter 表库处理空/空值
- ios - 应用程序与 iOS 模拟器上的数据库通信,但不在设备上
- vba - word文档的超链接在哪里?
- android - 是否可以在 TextInputLayout 中为错误标签保留空间?
- python - 如何从 Microsoft Visual Studio Code 中的 Python 交互选项卡保存图像
- google-sheets - 如何使行中的单元格显示该行中最近编辑的日期