WebSphere迁移至JBoss EAP7.1.0遇UT000068 Servlet路径匹配失败错误
刚帮团队搞定过类似的迁移坑,这个UT000068: Servlet path match failed异常本质是JBoss EAP7.1搭载的Undertow容器,对Servlet路径匹配的规则比WebSphere严格得多,尤其是和Struts的forward动作结合时很容易触发。先贴出你遇到的错误栈方便对照:
ERROR [default task-37] nmateti ActionExceptionHandler.logException(143) | java.lang.IllegalArgumentException: UT000068: Servlet path match failed at io.undertow.servlet.handlers.ServletPathMatchesData.getServletHandlerByPath(ServletPathMatchesData.java:83) at io.undertow.servlet.handlers.ServletPathMatches.getServletHandlerByPath(ServletPathMatches.java:88) at io.undertow.servlet.spec.RequestDispatcherImpl.<init>(RequestDispatcherImpl.java:74) at io.undertow.servlet.spec.ServletContextImpl.getRequestDispatcher(ServletContextImpl.java:330) at org.apache.struts.chain.commands.servlet.PerformForward.handleAsForward(PerformForward.java:93) at org.apache.struts.chain.commands.servlet.PerformForward.perform(PerformForward.java:82) at org.apache.struts.chain.commands.AbstractPerformForward.execute(AbstractPerformForward.java:51) at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:48) at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190) at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304) at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190) at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:280) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1858) at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:459) at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119) at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at com.wm.snapshot.webapp.filter.StackFilter.doFilter(StackFilter.java:52) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at com.wm.snapshot.webapp.filter.LogFilter.doFilter(LogFilter.java:93) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:264) at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107) at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274) at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:110) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274) at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274) at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:217) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274) at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:193) at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:274) at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:148) at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.ajaxanywhere.AAFilter.doFilter(AAFilter.java:65) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
问题根源
从栈信息能看到,Struts的PerformForward调用ServletContext.getRequestDispatcher时,Undertow找不到对应路径的Servlet映射。WebSphere对forward路径的校验非常宽松——哪怕是相对路径、没有明确映射的路径,它都能默认处理;但Undertow要求必须严格匹配已注册的Servlet/JSP映射规则,不满足就直接抛出异常。
具体解决方案
1. 规范Struts Forward路径
检查所有struts-config.xml里的forward配置,必须使用以/开头的绝对路径,比如:
<forward name="userDetail" path="/user/detail.jsp"/>
绝对不要用相对路径(比如user/detail.jsp)或者不带前缀的路径,Undertow会直接拒绝这种格式的forward请求。如果是在Action里动态生成forward路径,也要确保最终输出的是绝对路径。
2. 校验Web.xml的Servlet映射
确认你的JSP或目标Servlet的映射配置正确。比如JSP通常需要在web.xml里有如下映射:
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping>
如果forward的目标是自定义Servlet,要确保它的url-pattern完全覆盖你要forward的路径,Undertow不会处理没有映射的路径。
3. 临时放宽Undertow的路径校验(不推荐长期使用)
如果暂时没法修改所有路径配置,可以在JBoss的standalone.xml(或domain.xml)里修改Undertow配置,添加允许绝对路径forward的参数:
<subsystem xmlns="urn:jboss:domain:undertow:4.0"> <server name="default-server"> <host name="default-host" alias="localhost"> <!-- 新增这行配置 --> <setting name="allow-absolute-path-in-forward" value="true"/> </host> </server> </subsystem>
注意:这只是临时兼容方案,长期来看还是要规范路径配置,避免依赖容器的差异。
4. 排查过滤器干扰
栈里能看到Sitemesh、Acegi Security等过滤器,部分过滤器会修改request的URI或路径信息,导致forward时路径异常。可以临时禁用这些过滤器测试,如果错误消失,就需要调整过滤器的配置,确保它们不会干扰forward的路径处理。
调试技巧
可以在Action里添加日志,打印要forward的目标路径;或者把Undertow的日志级别调到DEBUG,这样能看到具体是哪个路径匹配失败,定位问题会更快。
内容的提问来源于stack exchange,提问作者professor

