文章目录


异常描述


java.lang.ClassCastException: org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade.UpgradeInbound
at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:842)
at org.apache.coyote.Request.action(Request.java:344)
at org.apache.catalina.connector.Request.doUpgrade(Request.java:2813)
at org.apache.catalina.connector.RequestFacade.doUpgrade(RequestFacade.java:1103)
at org.apache.catalina.websocket.WebSocketServlet.doGet(WebSocketServlet.java:131)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol A b s t r a c t C o n n e c t i o n H a n d l e r . p r o c e s s ( A b s t r a c t P r o t o c o l . j a v a : 585 ) a t o r g . a p a c h e . t o m c a t . u t i l . n e t . N i o E n d p o i n t AbstractConnectionHandler.process(AbstractProtocol.java:585) at .NioEndpoint AbstractConnectionHandler.process(AbstractProtocol.java:585)at.NioEndpointSocketProcessor.run(NioEndpoint.java:1653)
at java.util.concurrent.ThreadPoolExecutor W o r k e r . r u n T a s k ( T h r e a d P o o l E x e c u t o r . j a v a : 886 ) a t j a v a . u t i l . c o n c u r r e n t . T h r e a d P o o l E x e c u t o r Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor Worker.runTask(ThreadPoolExecutor.java:886)atjava.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)


​org.apache.coyote.Request​​​无法转换为​​org.apache.coyote.http11.upgrade.UpgradeInbound​​。

这个异常时有时无,出现的时候也不会影响系统的正常运行。

问题定位

首先从异常堆栈定位出现异常的源码位置。


at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:842)
at org.apache.coyote.Request.action(Request.java:344)
at org.apache.catalina.connector.Request.doUpgrade(Request.java:2813)
at org.apache.catalina.connector.RequestFacade.doUpgrade(RequestFacade.java:1103)
at org.apache.catalina.websocket.WebSocketServlet.doGet(WebSocketServlet.java:131)


1.​​org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:842)​​​ ,找到源码​​AbstractHttp11Processor.action​​​842行,​​this.upgradeInbound = ((UpgradeInbound)param);​​​,​​param​​​转为​​UpgradeInbound​​​出现类型不匹配。tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._apache

2.​​这时看看哪里调用了​​AbstractHttp11Processor.action​​。继续看异常堆栈org.apache.coyote.Request.action(Request.java:344)​​,找到​​org.apache.coyote.Request​​类第344行:

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._case study_02

343行代码会判断​​param​​​是否为null,​​param=null​​​,调用​​this.hook.action(actionCode, this);​​​第二个参数直接传了一个​​this​​​,这个​​this​​​就是​​org.apache.coyote.Request​​​。从这里就已经看出因为参数​​param=null​​​,直接把​​org.apache.coyote.Request​​​本身当作​​param​​​传给了​​hook.action()​​​,这个​​hook​​​就是​​org.apache.coyote.http11.AbstractHttp11Processor​​​。(​​AbstractHttp11Processor​​​继承了​​AbstractProcessor​​​,​​AbstractProcessor​​​实现了接口​​ActionHook​​)

3.继续深究,什么情况下​​org.apache.coyote.Request.action(ActionCode actionCode, Object param)​​​的第二个参数​​param​​等于null呢?

找到​​org.apache.catalina.connector.Request.doUpgrade(Request.java:2813)​​代码位置,可以看到该方法第二个参数​​UpgradeInbound inbound​​,也就验证了​​org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade.UpgradeInbound​​。

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._apache_03

4.​​at org.apache.catalina.connector.RequestFacade.doUpgrade(RequestFacade.java:1103)​

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._WebSocket_04

5.​​at org.apache.catalina.websocket.WebSocketServlet.doGet(WebSocketServlet.java:131)​​,从源码可以看到​​StreamInbound inbound = createWebSocketInbound(subProtocol, wrapper);​​,源头找到了,就是因为​​createWebSocketInbound​​这个方法创建的​​inbound​​可能等于null,然后就出现了后面类型转换的问题。

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._apache_05

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._WebSocket_06

protected abstract StreamInbound createWebSocketInbound(String paramString, HttpServletRequest paramHttpServletRequest);

public abstract class StreamInbound
implements UpgradeInbound{...}

​createWebSocketInbound​​是一个静态方法,使用tomcat的webSocket的功能,需要继承​​org.apache.catalina.websocket.WebSocketServlet​​,实现​​createWebSocketInbound​​,这个跟wesocket三次握手建立连接有关。查看项目代码,自行实现的​​createWebSocketInbound​​确实存在返回null的情况。

tomcat websocket类型转换异常:org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade._apache_07

原因分析

在使用tomcat的websocket 功能时,自行实现​​org.apache.catalina.websocket.WebSocketServlet#createWebSocketInbound​​​有存在返回null的情况,导致后面​​org.apache.coyote.Request.action(Request.java:344)​​​判断​​org.apache.coyote.http11.upgrade.UpgradeInbound​​​类型的参数为空时,将自己(​​this​​​)代替传了进去,从而出现了​​org.apache.coyote.Request cannot be cast to org.apache.coyote.http11.upgrade.UpgradeInbound​​的异常。

问题总结

在使用tomcat的websocket 功能时,继承​​org.apache.catalina.websocket.WebSocketServlet​​​,自行实现​​org.apache.catalina.websocket.WebSocketServlet#createWebSocketInbound​​时不能返回null。

PS: 如若文章中有错误理解,欢迎批评指正,同时非常期待你的评论、点赞和收藏。我是徐同学,愿与你共同进步!