为什么我的tomcat阀没有被调用?
我尝试实现一个Tomcat阀(目前使用的是7.0.55),它应该拦截到达Tomcat服务的每个请求,不管连接器和其他什么,不管是否有具有匹配名称的主机或servlet上下文或其他什么 阀门的为什么我的tomcat阀没有被调用?,tomcat,tomcat-valve,Tomcat,Tomcat Valve,我尝试实现一个Tomcat阀(目前使用的是7.0.55),它应该拦截到达Tomcat服务的每个请求,不管连接器和其他什么,不管是否有具有匹配名称的主机或servlet上下文或其他什么 阀门的invoke-方法如下所示: public class MyValve extends ValveBase { public void invoke(Request request, Response response) throws IOException, ServletE
invoke
-方法如下所示:
public class MyValve extends ValveBase {
public void invoke(Request request, Response response) throws IOException,
ServletException {
LOG.trace("Valve is being invoked");
getNext().invoke(request, response);
}
}
在开发系统上,在本地测试时,一切正常。对我的“localhost”tomcat上任何URI路径的请求都会写入该日志行。在server.xml
中,阀门在任何主机
元件外部配置:
<Server port="8005" shutdown="SHUTDOWN">
...
<Service name="Catalina">
...
<Engine defaultHost="localhost" name="Catalina">
...
<Realm ... />
<Valve className="a.b.c.MyValve" />
...
<Host ...>
</Host>
</Engine>
</Service>
</Server>
...
...
...
...
现在假设在我的系统的hosts文件中,域test.domain.com
映射到127.0.0.1,并且部署了一个名为somewebapp
的上下文
如上所述,当我调用http://localhost:8080/some-webapp/
,正如预期的那样,当我调用http://localhost:8080/non-现有webapp/
,这也是预期的。域(未在server.xml中配置)test.domain.com也是如此,因此
http://test.domain.com/some-webapp/
打印日志行以及http://test.domain.com/non-existing-webapp
但对于我们正在测试的服务器来说,情况并非如此。这里,只有当URI的上下文名称对tomcat来说是“已知”的时候,才会调用该阀,即对…/某个webapp/的调用会打印日志行,而对…/不存在的webapp/的调用则什么也不做-根本不会调用该阀。尽管如此,tomcat还是会处理该请求,因为发送到客户端的404在本例中包含“apachecoyotesomething”作为响应头 我不知道如何进一步调试它,特别是tomcat“选择”管道的过程,或者其他什么——有什么想法吗
谢谢 结果表明,这是由于Tomcat的webapps目录中缺少根目录造成的。我认为Tomcat在很早的时候就对传入的请求进行了相当严格的过滤,甚至在任何阀门能够处理和处理请求之前。
如果没有默认上下文(即没有根目录),Tomcat(认为)知道对不存在的webapp的请求不能成功,因此甚至不会调用阀门。在默认上下文中,Tomcat无法知道请求将发生什么,因此valve有机会拦截请求。在版本6中(不确定早期版本中会发生什么)-8如果Tomcat确定需要重定向,则不会调用valve,所以令人惊讶的是,只有在映射阶段确定上下文时,阀门才能可靠地工作 您可以检查执行操作的
org.apache.catalina.connector.CoyoteAdapter
类的源代码(如果愿意,还可以附加一个调试器)
// Parse and set Catalina and configuration specific
// request parameters
req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
boolean postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
正如您所看到的,只有在postParseRequest返回true时才会调用阀门,例如,如果Tomcat确定它应该在postParseRequest期间返回重定向,则不会发生这种情况。
确定需要重定向的代码:
// Possible redirect
MessageBytes redirectPathMB = request.getMappingData().redirectPath;
if (!redirectPathMB.isNull()) {
String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString());
String query = request.getQueryString();
if (request.isRequestedSessionIdFromURL()) {
// This is not optimal, but as this is not very common, it
// shouldn't matter
redirectPath = redirectPath + ";" +
SessionConfig.getSessionUriParamName(
request.getContext()) +
"=" + request.getRequestedSessionId();
}
if (query != null) {
// This is not optimal, but as this is not very common, it
// shouldn't matter
redirectPath = redirectPath + "?" + query;
}
response.sendRedirect(redirectPath);
request.getContext().logAccess(request, response, 0, true);
return false;
}
在我的例子中,重定向是在org.apache.catalina.mapper.mapper.internalMapWrapper(…)
如果使用RemoteIpValve,这可能会造成麻烦,因为它会导致Tomcat使用错误的模式发送重定向