问题描述
项目组有个web应用,部署在阿里云EDAS上,Tomcat版本是7.0.59.3。
项目组反馈在测试环境该工程所有接口都返回404,生产环境接口都能够正常访问。
测试环境与生产环境除了apollo上的配置不一样,其他都一样。报错信息如下:
问题分析
一、Controller类是否正确
首先想到的是Controller可能写法有问题,导致Spring没有加载到。通过arthas vmtool可以验证这个问题,如图2:
vmtool --action getInstances --className org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping --express 'instances[0].mappingRegistry.urlLookup' -x 1
从图2中可以看到Spring已经正确加载了Controller类。
二、Spring处理请求流程
是否是Spring在处理请求过程中,出现了问题导致返回的404?通过arthas watch可以验证这个问题,如图3:
watch org.springframework.web.servlet.FrameworkServlet service "{params[0].request.coyoteRequest}" -x 2
从图3中可以看到请求根本没有到达Spring处理流程中。
难道是Filter处理过程中出现了问题?通过arthas watch观察相关Filter类,发现请求也没有道道Filter的处理流程中。
三、Tomcat处理流程
请求没有到达Filter,可能在Tomcat处理的过程中出现了问题。
既然Tomcat 返回的是404,那么我们可以分析一下404是在哪个类中设置的,通过分析相关代码,设置状态码的方法如下:
/** * Set the response status */ public void setStatus( int status ) { this.status = status; }
接口通过arthas watch看一下我们的判断是否正确,如图4:
watch org.apache.coyote.Response setStatus "{params}" -x 2
从图4可知,状态码是通过org.apache.coyote.Response.setStatus设置的。
接着通过arthas stack看一下该方法的线程栈就可以请求整个处理流程了,如图5:
stack org.apache.coyote.Response setStatus
org.apache.coyote.http11.AbstractHttp11Processor.process
由于tomcat是alitomcat,没有源码,所以通过反编译进行分析。
org.apache.catalina.connector.CoyoteAdapter
接下来看一下postParseRequest方法相关逻辑,如下:
分析到这里,已经找到了问题的根因,所以解决办法就是把url中的路径写正确。